Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / content / browser / appcache / appcache_storage_impl_unittest.cc
blob37c295dbb433c09b4ca5f6150d480faaef914fb3
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.
5 #include <stack>
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/thread.h"
16 #include "content/browser/appcache/appcache.h"
17 #include "content/browser/appcache/appcache_backend_impl.h"
18 #include "content/browser/appcache/appcache_database.h"
19 #include "content/browser/appcache/appcache_entry.h"
20 #include "content/browser/appcache/appcache_group.h"
21 #include "content/browser/appcache/appcache_host.h"
22 #include "content/browser/appcache/appcache_interceptor.h"
23 #include "content/browser/appcache/appcache_request_handler.h"
24 #include "content/browser/appcache/appcache_service_impl.h"
25 #include "content/browser/appcache/appcache_storage_impl.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/request_priority.h"
28 #include "net/http/http_response_headers.h"
29 #include "net/url_request/url_request_error_job.h"
30 #include "net/url_request/url_request_job_factory_impl.h"
31 #include "net/url_request/url_request_test_job.h"
32 #include "net/url_request/url_request_test_util.h"
33 #include "sql/test/test_helpers.h"
34 #include "storage/browser/quota/quota_manager.h"
35 #include "testing/gtest/include/gtest/gtest.h"
37 namespace content {
39 namespace {
41 const base::Time kZeroTime;
42 const GURL kManifestUrl("http://blah/manifest");
43 const GURL kManifestUrl2("http://blah/manifest2");
44 const GURL kManifestUrl3("http://blah/manifest3");
45 const GURL kEntryUrl("http://blah/entry");
46 const GURL kEntryUrl2("http://blah/entry2");
47 const GURL kFallbackNamespace("http://blah/fallback_namespace/");
48 const GURL kFallbackNamespace2("http://blah/fallback_namespace/longer");
49 const GURL kFallbackTestUrl("http://blah/fallback_namespace/longer/test");
50 const GURL kOnlineNamespace("http://blah/online_namespace");
51 const GURL kOnlineNamespaceWithinFallback(
52 "http://blah/fallback_namespace/online/");
53 const GURL kInterceptNamespace("http://blah/intercept_namespace/");
54 const GURL kInterceptNamespace2("http://blah/intercept_namespace/longer/");
55 const GURL kInterceptTestUrl("http://blah/intercept_namespace/longer/test");
56 const GURL kInterceptPatternNamespace("http://blah/intercept_pattern/*/bar");
57 const GURL kInterceptPatternTestPositiveUrl(
58 "http://blah/intercept_pattern/foo/bar");
59 const GURL kInterceptPatternTestNegativeUrl(
60 "http://blah/intercept_pattern/foo/not_bar");
61 const GURL kFallbackPatternNamespace("http://blah/fallback_pattern/*/bar");
62 const GURL kFallbackPatternTestPositiveUrl(
63 "http://blah/fallback_pattern/foo/bar");
64 const GURL kFallbackPatternTestNegativeUrl(
65 "http://blah/fallback_pattern/foo/not_bar");
66 const GURL kOrigin(kManifestUrl.GetOrigin());
68 const int kManifestEntryIdOffset = 100;
69 const int kFallbackEntryIdOffset = 1000;
71 const GURL kDefaultEntryUrl("http://blah/makecacheandgroup_default_entry");
72 const int kDefaultEntrySize = 10;
73 const int kDefaultEntryIdOffset = 12345;
75 const int kMockQuota = 5000;
77 // The Reinitialize test needs some http accessible resources to run,
78 // we mock stuff inprocess for that.
79 class MockHttpServer {
80 public:
81 static GURL GetMockUrl(const std::string& path) {
82 return GURL("http://mockhost/" + path);
85 static net::URLRequestJob* CreateJob(
86 net::URLRequest* request, net::NetworkDelegate* network_delegate) {
87 if (request->url().host() != "mockhost")
88 return new net::URLRequestErrorJob(request, network_delegate, -100);
90 std::string headers, body;
91 GetMockResponse(request->url().path(), &headers, &body);
92 return new net::URLRequestTestJob(
93 request, network_delegate, headers, body, true);
96 private:
97 static void GetMockResponse(const std::string& path,
98 std::string* headers,
99 std::string* body) {
100 const char manifest_headers[] =
101 "HTTP/1.1 200 OK\0"
102 "Content-type: text/cache-manifest\0"
103 "\0";
104 const char page_headers[] =
105 "HTTP/1.1 200 OK\0"
106 "Content-type: text/html\0"
107 "\0";
108 const char not_found_headers[] =
109 "HTTP/1.1 404 NOT FOUND\0"
110 "\0";
112 if (path == "/manifest") {
113 (*headers) = std::string(manifest_headers, arraysize(manifest_headers));
114 (*body) = "CACHE MANIFEST\n";
115 } else if (path == "/empty.html") {
116 (*headers) = std::string(page_headers, arraysize(page_headers));
117 (*body) = "";
118 } else {
119 (*headers) = std::string(not_found_headers,
120 arraysize(not_found_headers));
121 (*body) = "";
126 class MockHttpServerJobFactory
127 : public net::URLRequestJobFactory::ProtocolHandler {
128 public:
129 MockHttpServerJobFactory(
130 scoped_ptr<net::URLRequestInterceptor> appcache_start_interceptor)
131 : appcache_start_interceptor_(appcache_start_interceptor.Pass()) {
134 net::URLRequestJob* MaybeCreateJob(
135 net::URLRequest* request,
136 net::NetworkDelegate* network_delegate) const override {
137 net::URLRequestJob* appcache_job =
138 appcache_start_interceptor_->MaybeInterceptRequest(
139 request, network_delegate);
140 if (appcache_job)
141 return appcache_job;
142 return MockHttpServer::CreateJob(request, network_delegate);
144 private:
145 scoped_ptr<net::URLRequestInterceptor> appcache_start_interceptor_;
148 class IOThread : public base::Thread {
149 public:
150 explicit IOThread(const char* name)
151 : base::Thread(name) {
154 ~IOThread() override { Stop(); }
156 net::URLRequestContext* request_context() {
157 return request_context_.get();
160 void Init() override {
161 scoped_ptr<net::URLRequestJobFactoryImpl> factory(
162 new net::URLRequestJobFactoryImpl());
163 factory->SetProtocolHandler(
164 "http",
165 new MockHttpServerJobFactory(
166 make_scoped_ptr(new AppCacheInterceptor())));
167 job_factory_ = factory.Pass();
168 request_context_.reset(new net::TestURLRequestContext());
169 request_context_->set_job_factory(job_factory_.get());
172 void CleanUp() override {
173 request_context_.reset();
174 job_factory_.reset();
177 private:
178 scoped_ptr<net::URLRequestJobFactory> job_factory_;
179 scoped_ptr<net::URLRequestContext> request_context_;
182 scoped_ptr<IOThread> io_thread;
183 scoped_ptr<base::Thread> db_thread;
185 } // namespace
187 class AppCacheStorageImplTest : public testing::Test {
188 public:
189 class MockStorageDelegate : public AppCacheStorage::Delegate {
190 public:
191 explicit MockStorageDelegate(AppCacheStorageImplTest* test)
192 : loaded_cache_id_(0), stored_group_success_(false),
193 would_exceed_quota_(false), obsoleted_success_(false),
194 found_cache_id_(kAppCacheNoCacheId), test_(test) {
197 void OnCacheLoaded(AppCache* cache, int64 cache_id) override {
198 loaded_cache_ = cache;
199 loaded_cache_id_ = cache_id;
200 test_->ScheduleNextTask();
203 void OnGroupLoaded(AppCacheGroup* group,
204 const GURL& manifest_url) override {
205 loaded_group_ = group;
206 loaded_manifest_url_ = manifest_url;
207 loaded_groups_newest_cache_ = group ? group->newest_complete_cache()
208 : NULL;
209 test_->ScheduleNextTask();
212 void OnGroupAndNewestCacheStored(AppCacheGroup* group,
213 AppCache* newest_cache,
214 bool success,
215 bool would_exceed_quota) override {
216 stored_group_ = group;
217 stored_group_success_ = success;
218 would_exceed_quota_ = would_exceed_quota;
219 test_->ScheduleNextTask();
222 void OnGroupMadeObsolete(AppCacheGroup* group,
223 bool success,
224 int response_code) override {
225 obsoleted_group_ = group;
226 obsoleted_success_ = success;
227 test_->ScheduleNextTask();
230 void OnMainResponseFound(const GURL& url,
231 const AppCacheEntry& entry,
232 const GURL& namespace_entry_url,
233 const AppCacheEntry& fallback_entry,
234 int64 cache_id,
235 int64 group_id,
236 const GURL& manifest_url) override {
237 found_url_ = url;
238 found_entry_ = entry;
239 found_namespace_entry_url_ = namespace_entry_url;
240 found_fallback_entry_ = fallback_entry;
241 found_cache_id_ = cache_id;
242 found_group_id_ = group_id;
243 found_manifest_url_ = manifest_url;
244 test_->ScheduleNextTask();
247 scoped_refptr<AppCache> loaded_cache_;
248 int64 loaded_cache_id_;
249 scoped_refptr<AppCacheGroup> loaded_group_;
250 GURL loaded_manifest_url_;
251 scoped_refptr<AppCache> loaded_groups_newest_cache_;
252 scoped_refptr<AppCacheGroup> stored_group_;
253 bool stored_group_success_;
254 bool would_exceed_quota_;
255 scoped_refptr<AppCacheGroup> obsoleted_group_;
256 bool obsoleted_success_;
257 GURL found_url_;
258 AppCacheEntry found_entry_;
259 GURL found_namespace_entry_url_;
260 AppCacheEntry found_fallback_entry_;
261 int64 found_cache_id_;
262 int64 found_group_id_;
263 GURL found_manifest_url_;
264 AppCacheStorageImplTest* test_;
267 class MockQuotaManager : public storage::QuotaManager {
268 public:
269 MockQuotaManager()
270 : QuotaManager(true /* is_incognito */,
271 base::FilePath(),
272 io_thread->message_loop_proxy().get(),
273 db_thread->message_loop_proxy().get(),
274 NULL),
275 async_(false) {}
277 void GetUsageAndQuota(const GURL& origin,
278 storage::StorageType type,
279 const GetUsageAndQuotaCallback& callback) override {
280 EXPECT_EQ(storage::kStorageTypeTemporary, type);
281 if (async_) {
282 base::MessageLoop::current()->PostTask(
283 FROM_HERE,
284 base::Bind(&MockQuotaManager::CallCallback,
285 base::Unretained(this),
286 callback));
287 return;
289 CallCallback(callback);
292 void CallCallback(const GetUsageAndQuotaCallback& callback) {
293 callback.Run(storage::kQuotaStatusOk, 0, kMockQuota);
296 bool async_;
298 protected:
299 ~MockQuotaManager() override {}
302 class MockQuotaManagerProxy : public storage::QuotaManagerProxy {
303 public:
304 MockQuotaManagerProxy()
305 : QuotaManagerProxy(NULL, NULL),
306 notify_storage_accessed_count_(0),
307 notify_storage_modified_count_(0),
308 last_delta_(0),
309 mock_manager_(new MockQuotaManager) {
310 manager_ = mock_manager_.get();
313 void NotifyStorageAccessed(storage::QuotaClient::ID client_id,
314 const GURL& origin,
315 storage::StorageType type) override {
316 EXPECT_EQ(storage::QuotaClient::kAppcache, client_id);
317 EXPECT_EQ(storage::kStorageTypeTemporary, type);
318 ++notify_storage_accessed_count_;
319 last_origin_ = origin;
322 void NotifyStorageModified(storage::QuotaClient::ID client_id,
323 const GURL& origin,
324 storage::StorageType type,
325 int64 delta) override {
326 EXPECT_EQ(storage::QuotaClient::kAppcache, client_id);
327 EXPECT_EQ(storage::kStorageTypeTemporary, type);
328 ++notify_storage_modified_count_;
329 last_origin_ = origin;
330 last_delta_ = delta;
333 // Not needed for our tests.
334 void RegisterClient(storage::QuotaClient* client) override {}
335 void NotifyOriginInUse(const GURL& origin) override {}
336 void NotifyOriginNoLongerInUse(const GURL& origin) override {}
337 void SetUsageCacheEnabled(storage::QuotaClient::ID client_id,
338 const GURL& origin,
339 storage::StorageType type,
340 bool enabled) override {}
341 void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner,
342 const GURL& origin,
343 storage::StorageType type,
344 const GetUsageAndQuotaCallback& callback) override {}
346 int notify_storage_accessed_count_;
347 int notify_storage_modified_count_;
348 GURL last_origin_;
349 int last_delta_;
350 scoped_refptr<MockQuotaManager> mock_manager_;
352 protected:
353 ~MockQuotaManagerProxy() override {}
356 template <class Method>
357 void RunMethod(Method method) {
358 (this->*method)();
361 // Helper callback to run a test on our io_thread. The io_thread is spun up
362 // once and reused for all tests.
363 template <class Method>
364 void MethodWrapper(Method method) {
365 SetUpTest();
367 // Ensure InitTask execution prior to conducting a test.
368 FlushDbThreadTasks();
370 // We also have to wait for InitTask completion call to be performed
371 // on the IO thread prior to running the test. Its guaranteed to be
372 // queued by this time.
373 base::MessageLoop::current()->PostTask(
374 FROM_HERE,
375 base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
376 base::Unretained(this),
377 method));
380 static void SetUpTestCase() {
381 // We start both threads as TYPE_IO because we also use the db_thead
382 // for the disk_cache which needs to be of TYPE_IO.
383 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
384 io_thread.reset(new IOThread("AppCacheTest.IOThread"));
385 ASSERT_TRUE(io_thread->StartWithOptions(options));
386 db_thread.reset(new base::Thread("AppCacheTest::DBThread"));
387 ASSERT_TRUE(db_thread->StartWithOptions(options));
390 static void TearDownTestCase() {
391 io_thread.reset(NULL);
392 db_thread.reset(NULL);
395 // Test harness --------------------------------------------------
397 AppCacheStorageImplTest() {
400 template <class Method>
401 void RunTestOnIOThread(Method method) {
402 test_finished_event_ .reset(new base::WaitableEvent(false, false));
403 io_thread->message_loop()->PostTask(
404 FROM_HERE, base::Bind(&AppCacheStorageImplTest::MethodWrapper<Method>,
405 base::Unretained(this), method));
406 test_finished_event_->Wait();
409 void SetUpTest() {
410 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
411 service_.reset(new AppCacheServiceImpl(NULL));
412 service_->Initialize(base::FilePath(), db_thread->task_runner(), NULL);
413 mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
414 service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
415 delegate_.reset(new MockStorageDelegate(this));
418 void TearDownTest() {
419 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
420 storage()->CancelDelegateCallbacks(delegate());
421 group_ = NULL;
422 cache_ = NULL;
423 cache2_ = NULL;
424 mock_quota_manager_proxy_ = NULL;
425 delegate_.reset();
426 service_.reset();
427 FlushDbThreadTasks();
430 void TestFinished() {
431 // We unwind the stack prior to finishing up to let stack
432 // based objects get deleted.
433 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
434 base::MessageLoop::current()->PostTask(
435 FROM_HERE,
436 base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
437 base::Unretained(this)));
440 void TestFinishedUnwound() {
441 TearDownTest();
442 test_finished_event_->Signal();
445 void PushNextTask(const base::Closure& task) {
446 task_stack_.push(task);
449 void ScheduleNextTask() {
450 DCHECK(base::MessageLoop::current() == io_thread->message_loop());
451 if (task_stack_.empty()) {
452 return;
454 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
455 task_stack_.pop();
458 static void SignalEvent(base::WaitableEvent* event) {
459 event->Signal();
462 void FlushDbThreadTasks() {
463 // We pump a task thru the db thread to ensure any tasks previously
464 // scheduled on that thread have been performed prior to return.
465 base::WaitableEvent event(false, false);
466 db_thread->message_loop()->PostTask(
467 FROM_HERE, base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
468 event.Wait();
471 // LoadCache_Miss ----------------------------------------------------
473 void LoadCache_Miss() {
474 // Attempt to load a cache that doesn't exist. Should
475 // complete asynchronously.
476 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Miss,
477 base::Unretained(this)));
479 storage()->LoadCache(111, delegate());
480 EXPECT_NE(111, delegate()->loaded_cache_id_);
483 void Verify_LoadCache_Miss() {
484 EXPECT_EQ(111, delegate()->loaded_cache_id_);
485 EXPECT_FALSE(delegate()->loaded_cache_.get());
486 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
487 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
488 TestFinished();
491 // LoadCache_NearHit -------------------------------------------------
493 void LoadCache_NearHit() {
494 // Attempt to load a cache that is currently in use
495 // and does not require loading from storage. This
496 // load should complete syncly.
498 // Setup some preconditions. Make an 'unstored' cache for
499 // us to load. The ctor should put it in the working set.
500 int64 cache_id = storage()->NewCacheId();
501 scoped_refptr<AppCache> cache(new AppCache(storage(), cache_id));
503 // Conduct the test.
504 storage()->LoadCache(cache_id, delegate());
505 EXPECT_EQ(cache_id, delegate()->loaded_cache_id_);
506 EXPECT_EQ(cache.get(), delegate()->loaded_cache_.get());
507 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
508 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
509 TestFinished();
512 // CreateGroup --------------------------------------------
514 void CreateGroupInEmptyOrigin() {
515 // Attempt to load a group that doesn't exist, one should
516 // be created for us, but not stored.
518 // Since the origin has no groups, the storage class will respond
519 // syncly.
520 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
521 Verify_CreateGroup();
524 void CreateGroupInPopulatedOrigin() {
525 // Attempt to load a group that doesn't exist, one should
526 // be created for us, but not stored.
527 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_CreateGroup,
528 base::Unretained(this)));
530 // Since the origin has groups, storage class will have to
531 // consult the database and completion will be async.
532 storage()->usage_map_[kOrigin] = kDefaultEntrySize;
534 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
535 EXPECT_FALSE(delegate()->loaded_group_.get());
538 void Verify_CreateGroup() {
539 EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
540 EXPECT_TRUE(delegate()->loaded_group_.get());
541 EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
542 EXPECT_FALSE(delegate()->loaded_group_->newest_complete_cache());
544 // Should not have been stored in the database.
545 AppCacheDatabase::GroupRecord record;
546 EXPECT_FALSE(database()->FindGroup(
547 delegate()->loaded_group_->group_id(), &record));
549 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
550 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
552 TestFinished();
555 // LoadGroupAndCache_FarHit --------------------------------------
557 void LoadGroupAndCache_FarHit() {
558 // Attempt to load a cache that is not currently in use
559 // and does require loading from disk. This
560 // load should complete asynchronously.
561 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Far_Hit,
562 base::Unretained(this)));
564 // Setup some preconditions. Create a group and newest cache that
565 // appear to be "stored" and "not currently in use".
566 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
567 group_ = NULL;
568 cache_ = NULL;
570 // Conduct the cache load test, completes async
571 storage()->LoadCache(1, delegate());
574 void Verify_LoadCache_Far_Hit() {
575 EXPECT_TRUE(delegate()->loaded_cache_.get());
576 EXPECT_TRUE(delegate()->loaded_cache_->HasOneRef());
577 EXPECT_EQ(1, delegate()->loaded_cache_id_);
579 // The group should also have been loaded.
580 EXPECT_TRUE(delegate()->loaded_cache_->owning_group());
581 EXPECT_TRUE(delegate()->loaded_cache_->owning_group()->HasOneRef());
582 EXPECT_EQ(1, delegate()->loaded_cache_->owning_group()->group_id());
584 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_accessed_count_);
585 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
587 // Drop things from the working set.
588 delegate()->loaded_cache_ = NULL;
589 EXPECT_FALSE(delegate()->loaded_group_.get());
591 // Conduct the group load test, also complete asynchronously.
592 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit,
593 base::Unretained(this)));
595 storage()->LoadOrCreateGroup(kManifestUrl, delegate());
598 void Verify_LoadGroup_Far_Hit() {
599 EXPECT_TRUE(delegate()->loaded_group_.get());
600 EXPECT_EQ(kManifestUrl, delegate()->loaded_manifest_url_);
601 EXPECT_TRUE(delegate()->loaded_group_->newest_complete_cache());
602 delegate()->loaded_groups_newest_cache_ = NULL;
603 EXPECT_TRUE(delegate()->loaded_group_->HasOneRef());
604 EXPECT_EQ(2, mock_quota_manager_proxy_->notify_storage_accessed_count_);
605 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
606 TestFinished();
609 // StoreNewGroup --------------------------------------
611 void StoreNewGroup() {
612 // Store a group and its newest cache. Should complete asynchronously.
613 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreNewGroup,
614 base::Unretained(this)));
616 // Setup some preconditions. Create a group and newest cache that
617 // appear to be "unstored".
618 group_ = new AppCacheGroup(
619 storage(), kManifestUrl, storage()->NewGroupId());
620 cache_ = new AppCache(storage(), storage()->NewCacheId());
621 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1,
622 kDefaultEntrySize));
623 // Hold a ref to the cache simulate the UpdateJob holding that ref,
624 // and hold a ref to the group to simulate the CacheHost holding that ref.
626 // Have the quota manager retrun asynchronously for this test.
627 mock_quota_manager_proxy_->mock_manager_->async_ = true;
629 // Conduct the store test.
630 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
631 EXPECT_FALSE(delegate()->stored_group_success_);
634 void Verify_StoreNewGroup() {
635 EXPECT_TRUE(delegate()->stored_group_success_);
636 EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
637 EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
638 EXPECT_TRUE(cache_->is_complete());
640 // Should have been stored in the database.
641 AppCacheDatabase::GroupRecord group_record;
642 AppCacheDatabase::CacheRecord cache_record;
643 EXPECT_TRUE(database()->FindGroup(group_->group_id(), &group_record));
644 EXPECT_TRUE(database()->FindCache(cache_->cache_id(), &cache_record));
646 // Verify quota bookkeeping
647 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
648 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
649 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
650 EXPECT_EQ(kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
652 TestFinished();
655 // StoreExistingGroup --------------------------------------
657 void StoreExistingGroup() {
658 // Store a group and its newest cache. Should complete asynchronously.
659 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreExistingGroup,
660 base::Unretained(this)));
662 // Setup some preconditions. Create a group and old complete cache
663 // that appear to be "stored"
664 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
665 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
667 // And a newest unstored complete cache.
668 cache2_ = new AppCache(storage(), 2);
669 cache2_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1,
670 kDefaultEntrySize + 100));
672 // Conduct the test.
673 storage()->StoreGroupAndNewestCache(
674 group_.get(), cache2_.get(), delegate());
675 EXPECT_FALSE(delegate()->stored_group_success_);
678 void Verify_StoreExistingGroup() {
679 EXPECT_TRUE(delegate()->stored_group_success_);
680 EXPECT_EQ(group_.get(), delegate()->stored_group_.get());
681 EXPECT_EQ(cache2_.get(), group_->newest_complete_cache());
682 EXPECT_TRUE(cache2_->is_complete());
684 // The new cache should have been stored in the database.
685 AppCacheDatabase::GroupRecord group_record;
686 AppCacheDatabase::CacheRecord cache_record;
687 EXPECT_TRUE(database()->FindGroup(1, &group_record));
688 EXPECT_TRUE(database()->FindCache(2, &cache_record));
690 // The old cache should have been deleted
691 EXPECT_FALSE(database()->FindCache(1, &cache_record));
693 // Verify quota bookkeeping
694 EXPECT_EQ(kDefaultEntrySize + 100, storage()->usage_map_[kOrigin]);
695 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
696 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
697 EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
699 TestFinished();
702 // StoreExistingGroupExistingCache -------------------------------
704 void StoreExistingGroupExistingCache() {
705 // Store a group with updates to its existing newest complete cache.
706 // Setup some preconditions. Create a group and a complete cache that
707 // appear to be "stored".
709 // Setup some preconditions. Create a group and old complete cache
710 // that appear to be "stored"
711 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
712 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
714 // Change the cache.
715 base::Time now = base::Time::Now();
716 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::MASTER, 1, 100));
717 cache_->set_update_time(now);
719 PushNextTask(base::Bind(
720 &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache,
721 base::Unretained(this), now));
723 // Conduct the test.
724 EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
725 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
726 EXPECT_FALSE(delegate()->stored_group_success_);
729 void Verify_StoreExistingGroupExistingCache(
730 base::Time expected_update_time) {
731 EXPECT_TRUE(delegate()->stored_group_success_);
732 EXPECT_EQ(cache_.get(), group_->newest_complete_cache());
734 AppCacheDatabase::CacheRecord cache_record;
735 EXPECT_TRUE(database()->FindCache(1, &cache_record));
736 EXPECT_EQ(1, cache_record.cache_id);
737 EXPECT_EQ(1, cache_record.group_id);
738 EXPECT_FALSE(cache_record.online_wildcard);
739 EXPECT_TRUE(expected_update_time == cache_record.update_time);
740 EXPECT_EQ(100 + kDefaultEntrySize, cache_record.cache_size);
742 std::vector<AppCacheDatabase::EntryRecord> entry_records;
743 EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records));
744 EXPECT_EQ(2U, entry_records.size());
745 if (entry_records[0].url == kDefaultEntryUrl)
746 entry_records.erase(entry_records.begin());
747 EXPECT_EQ(1 , entry_records[0].cache_id);
748 EXPECT_EQ(kEntryUrl, entry_records[0].url);
749 EXPECT_EQ(AppCacheEntry::MASTER, entry_records[0].flags);
750 EXPECT_EQ(1, entry_records[0].response_id);
751 EXPECT_EQ(100, entry_records[0].response_size);
753 // Verify quota bookkeeping
754 EXPECT_EQ(100 + kDefaultEntrySize, storage()->usage_map_[kOrigin]);
755 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
756 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
757 EXPECT_EQ(100, mock_quota_manager_proxy_->last_delta_);
759 TestFinished();
762 // FailStoreGroup --------------------------------------
764 void FailStoreGroup() {
765 // Store a group and its newest cache. Should complete asynchronously.
766 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FailStoreGroup,
767 base::Unretained(this)));
769 // Setup some preconditions. Create a group and newest cache that
770 // appear to be "unstored" and big enough to exceed the 5M limit.
771 const int64 kTooBig = 10 * 1024 * 1024; // 10M
772 group_ = new AppCacheGroup(
773 storage(), kManifestUrl, storage()->NewGroupId());
774 cache_ = new AppCache(storage(), storage()->NewCacheId());
775 cache_->AddEntry(kManifestUrl,
776 AppCacheEntry(AppCacheEntry::MANIFEST, 1, kTooBig));
777 // Hold a ref to the cache simulate the UpdateJob holding that ref,
778 // and hold a ref to the group to simulate the CacheHost holding that ref.
780 // Conduct the store test.
781 storage()->StoreGroupAndNewestCache(group_.get(), cache_.get(), delegate());
782 EXPECT_FALSE(delegate()->stored_group_success_); // Expected to be async.
785 void Verify_FailStoreGroup() {
786 EXPECT_FALSE(delegate()->stored_group_success_);
787 EXPECT_TRUE(delegate()->would_exceed_quota_);
789 // Should not have been stored in the database.
790 AppCacheDatabase::GroupRecord group_record;
791 AppCacheDatabase::CacheRecord cache_record;
792 EXPECT_FALSE(database()->FindGroup(group_->group_id(), &group_record));
793 EXPECT_FALSE(database()->FindCache(cache_->cache_id(), &cache_record));
795 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_accessed_count_);
796 EXPECT_EQ(0, mock_quota_manager_proxy_->notify_storage_modified_count_);
798 TestFinished();
801 // MakeGroupObsolete -------------------------------
803 void MakeGroupObsolete() {
804 // Make a group obsolete, should complete asynchronously.
805 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete,
806 base::Unretained(this)));
808 // Setup some preconditions. Create a group and newest cache that
809 // appears to be "stored" and "currently in use".
810 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
811 EXPECT_EQ(kDefaultEntrySize, storage()->usage_map_[kOrigin]);
813 // Also insert some related records.
814 AppCacheDatabase::EntryRecord entry_record;
815 entry_record.cache_id = 1;
816 entry_record.flags = AppCacheEntry::FALLBACK;
817 entry_record.response_id = 1;
818 entry_record.url = kEntryUrl;
819 EXPECT_TRUE(database()->InsertEntry(&entry_record));
821 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
822 fallback_namespace_record.cache_id = 1;
823 fallback_namespace_record.namespace_.target_url = kEntryUrl;
824 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
825 fallback_namespace_record.origin = kManifestUrl.GetOrigin();
826 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
828 AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record;
829 online_whitelist_record.cache_id = 1;
830 online_whitelist_record.namespace_url = kOnlineNamespace;
831 EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record));
833 // Conduct the test.
834 storage()->MakeGroupObsolete(group_.get(), delegate(), 0);
835 EXPECT_FALSE(group_->is_obsolete());
838 void Verify_MakeGroupObsolete() {
839 EXPECT_TRUE(delegate()->obsoleted_success_);
840 EXPECT_EQ(group_.get(), delegate()->obsoleted_group_.get());
841 EXPECT_TRUE(group_->is_obsolete());
842 EXPECT_TRUE(storage()->usage_map_.empty());
844 // The cache and group have been deleted from the database.
845 AppCacheDatabase::GroupRecord group_record;
846 AppCacheDatabase::CacheRecord cache_record;
847 EXPECT_FALSE(database()->FindGroup(1, &group_record));
848 EXPECT_FALSE(database()->FindCache(1, &cache_record));
850 // The related records should have been deleted too.
851 std::vector<AppCacheDatabase::EntryRecord> entry_records;
852 database()->FindEntriesForCache(1, &entry_records);
853 EXPECT_TRUE(entry_records.empty());
854 std::vector<AppCacheDatabase::NamespaceRecord> intercept_records;
855 std::vector<AppCacheDatabase::NamespaceRecord> fallback_records;
856 database()->FindNamespacesForCache(
857 1, &intercept_records, &fallback_records);
858 EXPECT_TRUE(fallback_records.empty());
859 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelist_records;
860 database()->FindOnlineWhiteListForCache(1, &whitelist_records);
861 EXPECT_TRUE(whitelist_records.empty());
863 // Verify quota bookkeeping
864 EXPECT_TRUE(storage()->usage_map_.empty());
865 EXPECT_EQ(1, mock_quota_manager_proxy_->notify_storage_modified_count_);
866 EXPECT_EQ(kOrigin, mock_quota_manager_proxy_->last_origin_);
867 EXPECT_EQ(-kDefaultEntrySize, mock_quota_manager_proxy_->last_delta_);
869 TestFinished();
872 // MarkEntryAsForeign -------------------------------
874 void MarkEntryAsForeign() {
875 // Setup some preconditions. Create a cache with an entry
876 // in storage and in the working set.
877 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
878 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
879 AppCacheDatabase::EntryRecord entry_record;
880 entry_record.cache_id = 1;
881 entry_record.url = kEntryUrl;
882 entry_record.flags = AppCacheEntry::EXPLICIT;
883 entry_record.response_id = 0;
884 EXPECT_TRUE(database()->InsertEntry(&entry_record));
885 EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
887 // Conduct the test.
888 storage()->MarkEntryAsForeign(kEntryUrl, 1);
890 // The entry in the working set should have been updated syncly.
891 EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsForeign());
892 EXPECT_TRUE(cache_->GetEntry(kEntryUrl)->IsExplicit());
894 // And the entry in storage should also be updated, but that
895 // happens asynchronously on the db thread.
896 FlushDbThreadTasks();
897 AppCacheDatabase::EntryRecord entry_record2;
898 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record2));
899 EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
900 entry_record2.flags);
901 TestFinished();
904 // MarkEntryAsForeignWithLoadInProgress -------------------------------
906 void MarkEntryAsForeignWithLoadInProgress() {
907 PushNextTask(base::Bind(
908 &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress,
909 base::Unretained(this)));
911 // Setup some preconditions. Create a cache with an entry
912 // in storage, but not in the working set.
913 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
914 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT));
915 AppCacheDatabase::EntryRecord entry_record;
916 entry_record.cache_id = 1;
917 entry_record.url = kEntryUrl;
918 entry_record.flags = AppCacheEntry::EXPLICIT;
919 entry_record.response_id = 0;
920 EXPECT_TRUE(database()->InsertEntry(&entry_record));
921 EXPECT_FALSE(cache_->GetEntry(kEntryUrl)->IsForeign());
922 EXPECT_TRUE(cache_->HasOneRef());
923 cache_ = NULL;
924 group_ = NULL;
926 // Conduct the test, start a cache load, and prior to completion
927 // of that load, mark the entry as foreign.
928 storage()->LoadCache(1, delegate());
929 storage()->MarkEntryAsForeign(kEntryUrl, 1);
932 void Verify_MarkEntryAsForeignWithLoadInProgress() {
933 EXPECT_EQ(1, delegate()->loaded_cache_id_);
934 EXPECT_TRUE(delegate()->loaded_cache_.get());
936 // The entry in the working set should have been updated upon load.
937 EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsForeign());
938 EXPECT_TRUE(delegate()->loaded_cache_->GetEntry(kEntryUrl)->IsExplicit());
940 // And the entry in storage should also be updated.
941 FlushDbThreadTasks();
942 AppCacheDatabase::EntryRecord entry_record;
943 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl, &entry_record));
944 EXPECT_EQ(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN,
945 entry_record.flags);
946 TestFinished();
949 // FindNoMainResponse -------------------------------
951 void FindNoMainResponse() {
952 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse,
953 base::Unretained(this)));
955 // Conduct the test.
956 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
957 EXPECT_NE(kEntryUrl, delegate()->found_url_);
960 void Verify_FindNoMainResponse() {
961 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
962 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
963 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
964 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
965 EXPECT_EQ(kAppCacheNoResponseId,
966 delegate()->found_fallback_entry_.response_id());
967 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
968 EXPECT_EQ(0, delegate()->found_entry_.types());
969 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
970 TestFinished();
973 // BasicFindMainResponse -------------------------------
975 void BasicFindMainResponseInDatabase() {
976 BasicFindMainResponse(true);
979 void BasicFindMainResponseInWorkingSet() {
980 BasicFindMainResponse(false);
983 void BasicFindMainResponse(bool drop_from_working_set) {
984 PushNextTask(base::Bind(
985 &AppCacheStorageImplTest::Verify_BasicFindMainResponse,
986 base::Unretained(this)));
988 // Setup some preconditions. Create a complete cache with an entry
989 // in storage.
990 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
991 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::EXPLICIT, 1));
992 AppCacheDatabase::EntryRecord entry_record;
993 entry_record.cache_id = 1;
994 entry_record.url = kEntryUrl;
995 entry_record.flags = AppCacheEntry::EXPLICIT;
996 entry_record.response_id = 1;
997 EXPECT_TRUE(database()->InsertEntry(&entry_record));
999 // Optionally drop the cache/group pair from the working set.
1000 if (drop_from_working_set) {
1001 EXPECT_TRUE(cache_->HasOneRef());
1002 cache_ = NULL;
1003 EXPECT_TRUE(group_->HasOneRef());
1004 group_ = NULL;
1007 // Conduct the test.
1008 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1009 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1012 void Verify_BasicFindMainResponse() {
1013 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1014 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1015 EXPECT_EQ(1, delegate()->found_cache_id_);
1016 EXPECT_EQ(2, delegate()->found_group_id_);
1017 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1018 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1019 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1020 TestFinished();
1023 // BasicFindMainFallbackResponse -------------------------------
1025 void BasicFindMainFallbackResponseInDatabase() {
1026 BasicFindMainFallbackResponse(true);
1029 void BasicFindMainFallbackResponseInWorkingSet() {
1030 BasicFindMainFallbackResponse(false);
1033 void BasicFindMainFallbackResponse(bool drop_from_working_set) {
1034 PushNextTask(base::Bind(
1035 &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse,
1036 base::Unretained(this)));
1038 // Setup some preconditions. Create a complete cache with a
1039 // fallback namespace and entry.
1040 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1041 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
1042 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
1043 cache_->fallback_namespaces_.push_back(
1044 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1045 kFallbackNamespace2,
1046 kEntryUrl2,
1047 false));
1048 cache_->fallback_namespaces_.push_back(
1049 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1050 kFallbackNamespace,
1051 kEntryUrl,
1052 false));
1053 AppCacheDatabase::CacheRecord cache_record;
1054 std::vector<AppCacheDatabase::EntryRecord> entries;
1055 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1056 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1057 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1058 cache_->ToDatabaseRecords(group_.get(),
1059 &cache_record,
1060 &entries,
1061 &intercepts,
1062 &fallbacks,
1063 &whitelists);
1065 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1066 entries.begin();
1067 while (iter != entries.end()) {
1068 // MakeCacheAndGroup has inserted the default entry record already.
1069 if (iter->url != kDefaultEntryUrl)
1070 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1071 ++iter;
1074 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
1075 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
1076 if (drop_from_working_set) {
1077 EXPECT_TRUE(cache_->HasOneRef());
1078 cache_ = NULL;
1079 EXPECT_TRUE(group_->HasOneRef());
1080 group_ = NULL;
1083 // Conduct the test. The test url is in both fallback namespace urls,
1084 // but should match the longer of the two.
1085 storage()->FindResponseForMainRequest(kFallbackTestUrl, GURL(), delegate());
1086 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1089 void Verify_BasicFindMainFallbackResponse() {
1090 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1091 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1092 EXPECT_EQ(1, delegate()->found_cache_id_);
1093 EXPECT_EQ(2, delegate()->found_group_id_);
1094 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1095 EXPECT_EQ(2, delegate()->found_fallback_entry_.response_id());
1096 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1097 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1098 TestFinished();
1101 // BasicFindMainInterceptResponse -------------------------------
1103 void BasicFindMainInterceptResponseInDatabase() {
1104 BasicFindMainInterceptResponse(true);
1107 void BasicFindMainInterceptResponseInWorkingSet() {
1108 BasicFindMainInterceptResponse(false);
1111 void BasicFindMainInterceptResponse(bool drop_from_working_set) {
1112 PushNextTask(base::Bind(
1113 &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse,
1114 base::Unretained(this)));
1116 // Setup some preconditions. Create a complete cache with an
1117 // intercept namespace and entry.
1118 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1119 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
1120 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::INTERCEPT, 2));
1121 cache_->intercept_namespaces_.push_back(
1122 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace2,
1123 kEntryUrl2, false));
1124 cache_->intercept_namespaces_.push_back(
1125 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE, kInterceptNamespace,
1126 kEntryUrl, false));
1127 AppCacheDatabase::CacheRecord cache_record;
1128 std::vector<AppCacheDatabase::EntryRecord> entries;
1129 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1130 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1131 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1132 cache_->ToDatabaseRecords(group_.get(),
1133 &cache_record,
1134 &entries,
1135 &intercepts,
1136 &fallbacks,
1137 &whitelists);
1139 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1140 entries.begin();
1141 while (iter != entries.end()) {
1142 // MakeCacheAndGroup has inserted the default entry record already
1143 if (iter->url != kDefaultEntryUrl)
1144 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1145 ++iter;
1148 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
1149 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists));
1150 if (drop_from_working_set) {
1151 EXPECT_TRUE(cache_->HasOneRef());
1152 cache_ = NULL;
1153 EXPECT_TRUE(group_->HasOneRef());
1154 group_ = NULL;
1157 // Conduct the test. The test url is in both intercept namespaces,
1158 // but should match the longer of the two.
1159 storage()->FindResponseForMainRequest(
1160 kInterceptTestUrl, GURL(), delegate());
1161 EXPECT_NE(kInterceptTestUrl, delegate()->found_url_);
1164 void Verify_BasicFindMainInterceptResponse() {
1165 EXPECT_EQ(kInterceptTestUrl, delegate()->found_url_);
1166 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1167 EXPECT_EQ(1, delegate()->found_cache_id_);
1168 EXPECT_EQ(2, delegate()->found_group_id_);
1169 EXPECT_EQ(2, delegate()->found_entry_.response_id());
1170 EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
1171 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1172 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1173 TestFinished();
1176 // FindInterceptPatternMatch ----------------------------------------
1178 void FindInterceptPatternMatchInDatabase() {
1179 FindInterceptPatternMatch(true);
1182 void FindInterceptPatternMatchInWorkingSet() {
1183 FindInterceptPatternMatch(false);
1186 void FindInterceptPatternMatch(bool drop_from_working_set) {
1187 // Setup some preconditions. Create a complete cache with an
1188 // pattern matching intercept namespace and entry.
1189 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1190 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::INTERCEPT, 1));
1191 cache_->intercept_namespaces_.push_back(
1192 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE,
1193 kInterceptPatternNamespace, kEntryUrl, true));
1194 AppCacheDatabase::CacheRecord cache_record;
1195 std::vector<AppCacheDatabase::EntryRecord> entries;
1196 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1197 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1198 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1199 cache_->ToDatabaseRecords(group_.get(),
1200 &cache_record,
1201 &entries,
1202 &intercepts,
1203 &fallbacks,
1204 &whitelists);
1206 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1207 entries.begin();
1208 while (iter != entries.end()) {
1209 // MakeCacheAndGroup has inserted the default entry record already
1210 if (iter->url != kDefaultEntryUrl)
1211 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1212 ++iter;
1215 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts));
1216 if (drop_from_working_set) {
1217 EXPECT_TRUE(cache_->HasOneRef());
1218 cache_ = NULL;
1219 EXPECT_TRUE(group_->HasOneRef());
1220 group_ = NULL;
1223 // First test something that does not match the pattern.
1224 PushNextTask(base::Bind(
1225 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative,
1226 base::Unretained(this)));
1227 storage()->FindResponseForMainRequest(
1228 kInterceptPatternTestNegativeUrl, GURL(), delegate());
1229 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
1232 void Verify_FindInterceptPatternMatchNegative() {
1233 EXPECT_EQ(kInterceptPatternTestNegativeUrl, delegate()->found_url_);
1234 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1235 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1236 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1237 EXPECT_EQ(kAppCacheNoResponseId,
1238 delegate()->found_fallback_entry_.response_id());
1239 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1240 EXPECT_EQ(0, delegate()->found_entry_.types());
1241 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1243 // Then test something that matches.
1244 PushNextTask(base::Bind(
1245 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive,
1246 base::Unretained(this)));
1247 storage()->FindResponseForMainRequest(
1248 kInterceptPatternTestPositiveUrl, GURL(), delegate());
1251 void Verify_FindInterceptPatternMatchPositive() {
1252 EXPECT_EQ(kInterceptPatternTestPositiveUrl, delegate()->found_url_);
1253 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1254 EXPECT_EQ(1, delegate()->found_cache_id_);
1255 EXPECT_EQ(2, delegate()->found_group_id_);
1256 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1257 EXPECT_TRUE(delegate()->found_entry_.IsIntercept());
1258 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
1259 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1260 TestFinished();
1263 // FindFallbackPatternMatch -------------------------------
1265 void FindFallbackPatternMatchInDatabase() {
1266 FindFallbackPatternMatch(true);
1269 void FindFallbackPatternMatchInWorkingSet() {
1270 FindFallbackPatternMatch(false);
1273 void FindFallbackPatternMatch(bool drop_from_working_set) {
1274 // Setup some preconditions. Create a complete cache with a
1275 // pattern matching fallback namespace and entry.
1276 MakeCacheAndGroup(kManifestUrl, 2, 1, true);
1277 cache_->AddEntry(kEntryUrl, AppCacheEntry(AppCacheEntry::FALLBACK, 1));
1278 cache_->fallback_namespaces_.push_back(
1279 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1280 kFallbackPatternNamespace, kEntryUrl, true));
1281 AppCacheDatabase::CacheRecord cache_record;
1282 std::vector<AppCacheDatabase::EntryRecord> entries;
1283 std::vector<AppCacheDatabase::NamespaceRecord> intercepts;
1284 std::vector<AppCacheDatabase::NamespaceRecord> fallbacks;
1285 std::vector<AppCacheDatabase::OnlineWhiteListRecord> whitelists;
1286 cache_->ToDatabaseRecords(group_.get(),
1287 &cache_record,
1288 &entries,
1289 &intercepts,
1290 &fallbacks,
1291 &whitelists);
1293 std::vector<AppCacheDatabase::EntryRecord>::const_iterator iter =
1294 entries.begin();
1295 while (iter != entries.end()) {
1296 // MakeCacheAndGroup has inserted the default entry record already.
1297 if (iter->url != kDefaultEntryUrl)
1298 EXPECT_TRUE(database()->InsertEntry(&(*iter)));
1299 ++iter;
1302 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks));
1303 if (drop_from_working_set) {
1304 EXPECT_TRUE(cache_->HasOneRef());
1305 cache_ = NULL;
1306 EXPECT_TRUE(group_->HasOneRef());
1307 group_ = NULL;
1310 // First test something that does not match the pattern.
1311 PushNextTask(base::Bind(
1312 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative,
1313 base::Unretained(this)));
1314 storage()->FindResponseForMainRequest(
1315 kFallbackPatternTestNegativeUrl, GURL(), delegate());
1316 EXPECT_EQ(GURL(), delegate()->found_url_); // Is always async.
1319 void Verify_FindFallbackPatternMatchNegative() {
1320 EXPECT_EQ(kFallbackPatternTestNegativeUrl, delegate()->found_url_);
1321 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1322 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1323 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1324 EXPECT_EQ(kAppCacheNoResponseId,
1325 delegate()->found_fallback_entry_.response_id());
1326 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1327 EXPECT_EQ(0, delegate()->found_entry_.types());
1328 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1330 // Then test something that matches.
1331 PushNextTask(base::Bind(
1332 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive,
1333 base::Unretained(this)));
1334 storage()->FindResponseForMainRequest(
1335 kFallbackPatternTestPositiveUrl, GURL(), delegate());
1338 void Verify_FindFallbackPatternMatchPositive() {
1339 EXPECT_EQ(kFallbackPatternTestPositiveUrl, delegate()->found_url_);
1340 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1341 EXPECT_EQ(1, delegate()->found_cache_id_);
1342 EXPECT_EQ(2, delegate()->found_group_id_);
1343 EXPECT_EQ(1, delegate()->found_fallback_entry_.response_id());
1344 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1345 EXPECT_EQ(kEntryUrl, delegate()->found_namespace_entry_url_);
1346 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1347 TestFinished();
1350 // FindMainResponseWithMultipleHits -------------------------------
1352 void FindMainResponseWithMultipleHits() {
1353 PushNextTask(base::Bind(
1354 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits,
1355 base::Unretained(this)));
1357 // Setup some preconditions, create a few caches with an identical set
1358 // of entries and fallback namespaces. Only the last one remains in
1359 // the working set to simulate appearing as "in use".
1360 MakeMultipleHitCacheAndGroup(kManifestUrl, 1);
1361 MakeMultipleHitCacheAndGroup(kManifestUrl2, 2);
1362 MakeMultipleHitCacheAndGroup(kManifestUrl3, 3);
1364 // Conduct the test, we should find the response from the last cache
1365 // since it's "in use".
1366 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1367 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1370 void MakeMultipleHitCacheAndGroup(const GURL& manifest_url, int id) {
1371 MakeCacheAndGroup(manifest_url, id, id, true);
1372 AppCacheDatabase::EntryRecord entry_record;
1374 // Add an entry for kEntryUrl
1375 entry_record.cache_id = id;
1376 entry_record.url = kEntryUrl;
1377 entry_record.flags = AppCacheEntry::EXPLICIT;
1378 entry_record.response_id = id;
1379 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1380 cache_->AddEntry(
1381 entry_record.url,
1382 AppCacheEntry(entry_record.flags, entry_record.response_id));
1384 // Add an entry for the manifestUrl
1385 entry_record.cache_id = id;
1386 entry_record.url = manifest_url;
1387 entry_record.flags = AppCacheEntry::MANIFEST;
1388 entry_record.response_id = id + kManifestEntryIdOffset;
1389 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1390 cache_->AddEntry(
1391 entry_record.url,
1392 AppCacheEntry(entry_record.flags, entry_record.response_id));
1394 // Add a fallback entry and namespace
1395 entry_record.cache_id = id;
1396 entry_record.url = kEntryUrl2;
1397 entry_record.flags = AppCacheEntry::FALLBACK;
1398 entry_record.response_id = id + kFallbackEntryIdOffset;
1399 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1400 cache_->AddEntry(
1401 entry_record.url,
1402 AppCacheEntry(entry_record.flags, entry_record.response_id));
1403 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
1404 fallback_namespace_record.cache_id = id;
1405 fallback_namespace_record.namespace_.target_url = entry_record.url;
1406 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
1407 fallback_namespace_record.origin = manifest_url.GetOrigin();
1408 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
1409 cache_->fallback_namespaces_.push_back(
1410 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1411 kFallbackNamespace,
1412 kEntryUrl2,
1413 false));
1416 void Verify_FindMainResponseWithMultipleHits() {
1417 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1418 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
1419 EXPECT_EQ(3, delegate()->found_cache_id_);
1420 EXPECT_EQ(3, delegate()->found_group_id_);
1421 EXPECT_EQ(3, delegate()->found_entry_.response_id());
1422 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1423 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1425 // Conduct another test preferring kManifestUrl
1426 delegate_.reset(new MockStorageDelegate(this));
1427 PushNextTask(base::Bind(
1428 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2,
1429 base::Unretained(this)));
1430 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl, delegate());
1431 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1434 void Verify_FindMainResponseWithMultipleHits2() {
1435 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1436 EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
1437 EXPECT_EQ(1, delegate()->found_cache_id_);
1438 EXPECT_EQ(1, delegate()->found_group_id_);
1439 EXPECT_EQ(1, delegate()->found_entry_.response_id());
1440 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1441 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1443 // Conduct the another test preferring kManifestUrl2
1444 delegate_.reset(new MockStorageDelegate(this));
1445 PushNextTask(base::Bind(
1446 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3,
1447 base::Unretained(this)));
1448 storage()->FindResponseForMainRequest(kEntryUrl, kManifestUrl2, delegate());
1449 EXPECT_NE(kEntryUrl, delegate()->found_url_);
1452 void Verify_FindMainResponseWithMultipleHits3() {
1453 EXPECT_EQ(kEntryUrl, delegate()->found_url_);
1454 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
1455 EXPECT_EQ(2, delegate()->found_cache_id_);
1456 EXPECT_EQ(2, delegate()->found_group_id_);
1457 EXPECT_EQ(2, delegate()->found_entry_.response_id());
1458 EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
1459 EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
1461 // Conduct another test with no preferred manifest that hits the fallback.
1462 delegate_.reset(new MockStorageDelegate(this));
1463 PushNextTask(base::Bind(
1464 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4,
1465 base::Unretained(this)));
1466 storage()->FindResponseForMainRequest(
1467 kFallbackTestUrl, GURL(), delegate());
1468 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1471 void Verify_FindMainResponseWithMultipleHits4() {
1472 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1473 EXPECT_EQ(kManifestUrl3, delegate()->found_manifest_url_);
1474 EXPECT_EQ(3, delegate()->found_cache_id_);
1475 EXPECT_EQ(3, delegate()->found_group_id_);
1476 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1477 EXPECT_EQ(3 + kFallbackEntryIdOffset,
1478 delegate()->found_fallback_entry_.response_id());
1479 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1480 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1482 // Conduct another test preferring kManifestUrl2 that hits the fallback.
1483 delegate_.reset(new MockStorageDelegate(this));
1484 PushNextTask(base::Bind(
1485 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5,
1486 base::Unretained(this)));
1487 storage()->FindResponseForMainRequest(
1488 kFallbackTestUrl, kManifestUrl2, delegate());
1489 EXPECT_NE(kFallbackTestUrl, delegate()->found_url_);
1492 void Verify_FindMainResponseWithMultipleHits5() {
1493 EXPECT_EQ(kFallbackTestUrl, delegate()->found_url_);
1494 EXPECT_EQ(kManifestUrl2, delegate()->found_manifest_url_);
1495 EXPECT_EQ(2, delegate()->found_cache_id_);
1496 EXPECT_EQ(2, delegate()->found_group_id_);
1497 EXPECT_FALSE(delegate()->found_entry_.has_response_id());
1498 EXPECT_EQ(2 + kFallbackEntryIdOffset,
1499 delegate()->found_fallback_entry_.response_id());
1500 EXPECT_TRUE(delegate()->found_fallback_entry_.IsFallback());
1501 EXPECT_EQ(kEntryUrl2, delegate()->found_namespace_entry_url_);
1503 TestFinished();
1506 // FindMainResponseExclusions -------------------------------
1508 void FindMainResponseExclusionsInDatabase() {
1509 FindMainResponseExclusions(true);
1512 void FindMainResponseExclusionsInWorkingSet() {
1513 FindMainResponseExclusions(false);
1516 void FindMainResponseExclusions(bool drop_from_working_set) {
1517 // Setup some preconditions. Create a complete cache with a
1518 // foreign entry, an online namespace, and a second online
1519 // namespace nested within a fallback namespace.
1520 MakeCacheAndGroup(kManifestUrl, 1, 1, true);
1521 cache_->AddEntry(kEntryUrl,
1522 AppCacheEntry(AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN, 1));
1523 cache_->AddEntry(kEntryUrl2, AppCacheEntry(AppCacheEntry::FALLBACK, 2));
1524 cache_->fallback_namespaces_.push_back(
1525 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE,
1526 kFallbackNamespace,
1527 kEntryUrl2,
1528 false));
1529 cache_->online_whitelist_namespaces_.push_back(
1530 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE, kOnlineNamespace,
1531 GURL(), false));
1532 cache_->online_whitelist_namespaces_.push_back(
1533 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE,
1534 kOnlineNamespaceWithinFallback, GURL(), false));
1536 AppCacheDatabase::EntryRecord entry_record;
1537 entry_record.cache_id = 1;
1538 entry_record.url = kEntryUrl;
1539 entry_record.flags = AppCacheEntry::EXPLICIT | AppCacheEntry::FOREIGN;
1540 entry_record.response_id = 1;
1541 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1542 AppCacheDatabase::OnlineWhiteListRecord whitelist_record;
1543 whitelist_record.cache_id = 1;
1544 whitelist_record.namespace_url = kOnlineNamespace;
1545 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
1546 AppCacheDatabase::NamespaceRecord fallback_namespace_record;
1547 fallback_namespace_record.cache_id = 1;
1548 fallback_namespace_record.namespace_.target_url = kEntryUrl2;
1549 fallback_namespace_record.namespace_.namespace_url = kFallbackNamespace;
1550 fallback_namespace_record.origin = kManifestUrl.GetOrigin();
1551 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record));
1552 whitelist_record.cache_id = 1;
1553 whitelist_record.namespace_url = kOnlineNamespaceWithinFallback;
1554 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record));
1555 if (drop_from_working_set) {
1556 cache_ = NULL;
1557 group_ = NULL;
1560 // We should not find anything for the foreign entry.
1561 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
1562 base::Unretained(this), kEntryUrl, 1));
1563 storage()->FindResponseForMainRequest(kEntryUrl, GURL(), delegate());
1566 void Verify_ExclusionNotFound(GURL expected_url, int phase) {
1567 EXPECT_EQ(expected_url, delegate()->found_url_);
1568 EXPECT_TRUE(delegate()->found_manifest_url_.is_empty());
1569 EXPECT_EQ(kAppCacheNoCacheId, delegate()->found_cache_id_);
1570 EXPECT_EQ(0, delegate()->found_group_id_);
1571 EXPECT_EQ(kAppCacheNoResponseId, delegate()->found_entry_.response_id());
1572 EXPECT_EQ(kAppCacheNoResponseId,
1573 delegate()->found_fallback_entry_.response_id());
1574 EXPECT_TRUE(delegate()->found_namespace_entry_url_.is_empty());
1575 EXPECT_EQ(0, delegate()->found_entry_.types());
1576 EXPECT_EQ(0, delegate()->found_fallback_entry_.types());
1578 if (phase == 1) {
1579 // We should not find anything for the online namespace.
1580 PushNextTask(
1581 base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound,
1582 base::Unretained(this), kOnlineNamespace, 2));
1583 storage()->FindResponseForMainRequest(
1584 kOnlineNamespace, GURL(), delegate());
1585 return;
1587 if (phase == 2) {
1588 // We should not find anything for the online namespace nested within
1589 // the fallback namespace.
1590 PushNextTask(base::Bind(
1591 &AppCacheStorageImplTest::Verify_ExclusionNotFound,
1592 base::Unretained(this), kOnlineNamespaceWithinFallback, 3));
1593 storage()->FindResponseForMainRequest(
1594 kOnlineNamespaceWithinFallback, GURL(), delegate());
1595 return;
1598 TestFinished();
1601 // Reinitialize -------------------------------
1602 // These tests are somewhat of a system integration test.
1603 // They rely on running a mock http server on our IO thread,
1604 // and involves other appcache classes to get some code
1605 // coverage thruout when Reinitialize happens.
1607 class MockServiceObserver : public AppCacheServiceImpl::Observer {
1608 public:
1609 explicit MockServiceObserver(AppCacheStorageImplTest* test)
1610 : test_(test) {}
1612 void OnServiceReinitialized(
1613 AppCacheStorageReference* old_storage_ref) override {
1614 observed_old_storage_ = old_storage_ref;
1615 test_->ScheduleNextTask();
1618 scoped_refptr<AppCacheStorageReference> observed_old_storage_;
1619 AppCacheStorageImplTest* test_;
1622 class MockAppCacheFrontend : public AppCacheFrontend {
1623 public:
1624 MockAppCacheFrontend() : error_event_was_raised_(false) {}
1626 void OnCacheSelected(int host_id, const AppCacheInfo& info) override {}
1627 void OnStatusChanged(const std::vector<int>& host_ids,
1628 AppCacheStatus status) override {}
1629 void OnEventRaised(const std::vector<int>& host_ids,
1630 AppCacheEventID event_id) override {}
1631 void OnProgressEventRaised(const std::vector<int>& host_ids,
1632 const GURL& url,
1633 int num_total,
1634 int num_complete) override {}
1635 void OnErrorEventRaised(const std::vector<int>& host_ids,
1636 const AppCacheErrorDetails& details) override {
1637 error_event_was_raised_ = true;
1639 void OnLogMessage(int host_id,
1640 AppCacheLogLevel log_level,
1641 const std::string& message) override {}
1642 void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
1644 bool error_event_was_raised_;
1647 enum ReinitTestCase {
1648 CORRUPT_CACHE_ON_INSTALL,
1649 CORRUPT_CACHE_ON_LOAD_EXISTING,
1650 CORRUPT_SQL_ON_INSTALL
1653 void Reinitialize1() {
1654 // Recover from a corrupt disk cache discovered while
1655 // installing a new appcache.
1656 Reinitialize(CORRUPT_CACHE_ON_INSTALL);
1659 void Reinitialize2() {
1660 // Recover from a corrupt disk cache discovered while
1661 // trying to load a resource from an existing appcache.
1662 Reinitialize(CORRUPT_CACHE_ON_LOAD_EXISTING);
1665 void Reinitialize3() {
1666 // Recover from a corrupt sql database discovered while
1667 // installing a new appcache.
1668 Reinitialize(CORRUPT_SQL_ON_INSTALL);
1671 void Reinitialize(ReinitTestCase test_case) {
1672 // Unlike all of the other tests, this one actually read/write files.
1673 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
1675 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
1676 EXPECT_TRUE(db.LazyOpen(true));
1678 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1679 test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
1680 // Create a corrupt/unopenable disk_cache index file.
1681 const std::string kCorruptData("deadbeef");
1682 base::FilePath disk_cache_directory =
1683 temp_directory_.path().AppendASCII("Cache");
1684 ASSERT_TRUE(base::CreateDirectory(disk_cache_directory));
1685 base::FilePath index_file = disk_cache_directory.AppendASCII("index");
1686 EXPECT_EQ(static_cast<int>(kCorruptData.length()),
1687 base::WriteFile(
1688 index_file, kCorruptData.data(), kCorruptData.length()));
1691 // Create records for a degenerate cached manifest that only contains
1692 // one entry for the manifest file resource.
1693 if (test_case == CORRUPT_CACHE_ON_LOAD_EXISTING) {
1694 AppCacheDatabase db(temp_directory_.path().AppendASCII("Index"));
1695 GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
1697 AppCacheDatabase::GroupRecord group_record;
1698 group_record.group_id = 1;
1699 group_record.manifest_url = manifest_url;
1700 group_record.origin = manifest_url.GetOrigin();
1701 EXPECT_TRUE(db.InsertGroup(&group_record));
1702 AppCacheDatabase::CacheRecord cache_record;
1703 cache_record.cache_id = 1;
1704 cache_record.group_id = 1;
1705 cache_record.online_wildcard = false;
1706 cache_record.update_time = kZeroTime;
1707 cache_record.cache_size = kDefaultEntrySize;
1708 EXPECT_TRUE(db.InsertCache(&cache_record));
1709 AppCacheDatabase::EntryRecord entry_record;
1710 entry_record.cache_id = 1;
1711 entry_record.url = manifest_url;
1712 entry_record.flags = AppCacheEntry::MANIFEST;
1713 entry_record.response_id = 1;
1714 entry_record.response_size = kDefaultEntrySize;
1715 EXPECT_TRUE(db.InsertEntry(&entry_record));
1718 // Recreate the service to point at the db and corruption on disk.
1719 service_.reset(new AppCacheServiceImpl(NULL));
1720 service_->set_request_context(io_thread->request_context());
1721 service_->Initialize(temp_directory_.path(),
1722 db_thread->task_runner(),
1723 db_thread->task_runner());
1724 mock_quota_manager_proxy_ = new MockQuotaManagerProxy();
1725 service_->quota_manager_proxy_ = mock_quota_manager_proxy_;
1726 delegate_.reset(new MockStorageDelegate(this));
1728 // Additional setup to observe reinitailize happens.
1729 observer_.reset(new MockServiceObserver(this));
1730 service_->AddObserver(observer_.get());
1732 // We continue after the init task is complete including the callback
1733 // on the current thread.
1734 FlushDbThreadTasks();
1735 base::MessageLoop::current()->PostTask(
1736 FROM_HERE,
1737 base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
1738 base::Unretained(this),
1739 test_case));
1742 void Continue_Reinitialize(ReinitTestCase test_case) {
1743 const int kMockProcessId = 1;
1744 backend_.reset(new AppCacheBackendImpl);
1745 backend_->Initialize(service_.get(), &frontend_, kMockProcessId);
1747 if (test_case == CORRUPT_SQL_ON_INSTALL) {
1748 // Break the db file
1749 EXPECT_FALSE(database()->was_corruption_detected());
1750 ASSERT_TRUE(sql::test::CorruptSizeInHeader(
1751 temp_directory_.path().AppendASCII("Index")));
1754 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1755 test_case == CORRUPT_SQL_ON_INSTALL) {
1756 // Try to create a new appcache, the resulting update job will
1757 // eventually fail when it gets to disk cache initialization.
1758 backend_->RegisterHost(1);
1759 AppCacheHost* host1 = backend_->GetHost(1);
1760 const GURL kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
1761 host1->first_party_url_ = kEmptyPageUrl;
1762 host1->SelectCache(kEmptyPageUrl,
1763 kAppCacheNoCacheId,
1764 MockHttpServer::GetMockUrl("manifest"));
1765 } else {
1766 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
1767 // Try to access the existing cache manifest.
1768 // The URLRequestJob will eventually fail when it gets to disk
1769 // cache initialization.
1770 backend_->RegisterHost(2);
1771 AppCacheHost* host2 = backend_->GetHost(2);
1772 GURL manifest_url = MockHttpServer::GetMockUrl("manifest");
1773 request_ = service()->request_context()->CreateRequest(
1774 manifest_url, net::DEFAULT_PRIORITY, NULL);
1775 AppCacheInterceptor::SetExtraRequestInfo(
1776 request_.get(), service_.get(),
1777 backend_->process_id(), host2->host_id(),
1778 RESOURCE_TYPE_MAIN_FRAME,
1779 false);
1780 request_->Start();
1783 PushNextTask(base::Bind(
1784 &AppCacheStorageImplTest::Verify_Reinitialized,
1785 base::Unretained(this),
1786 test_case));
1789 void Verify_Reinitialized(ReinitTestCase test_case) {
1790 // Verify we got notified of reinit and a new storage instance is created,
1791 // and that the old data has been deleted.
1792 EXPECT_TRUE(observer_->observed_old_storage_.get());
1793 EXPECT_TRUE(observer_->observed_old_storage_->storage() != storage());
1794 EXPECT_FALSE(PathExists(
1795 temp_directory_.path().AppendASCII("Cache").AppendASCII("index")));
1796 EXPECT_FALSE(PathExists(
1797 temp_directory_.path().AppendASCII("Index")));
1799 if (test_case == CORRUPT_SQL_ON_INSTALL) {
1800 AppCacheStorageImpl* storage = static_cast<AppCacheStorageImpl*>(
1801 observer_->observed_old_storage_->storage());
1802 EXPECT_TRUE(storage->database_->was_corruption_detected());
1805 // Verify that the hosts saw appropriate events.
1806 if (test_case == CORRUPT_CACHE_ON_INSTALL ||
1807 test_case == CORRUPT_SQL_ON_INSTALL) {
1808 EXPECT_TRUE(frontend_.error_event_was_raised_);
1809 AppCacheHost* host1 = backend_->GetHost(1);
1810 EXPECT_FALSE(host1->associated_cache());
1811 EXPECT_FALSE(host1->group_being_updated_.get());
1812 EXPECT_TRUE(host1->disabled_storage_reference_.get());
1813 } else {
1814 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING, test_case);
1815 AppCacheHost* host2 = backend_->GetHost(2);
1816 EXPECT_EQ(1, host2->main_resource_cache_->cache_id());
1817 EXPECT_TRUE(host2->disabled_storage_reference_.get());
1820 // Cleanup and claim victory.
1821 service_->RemoveObserver(observer_.get());
1822 request_.reset();
1823 backend_.reset();
1824 observer_.reset();
1825 TestFinished();
1828 // Test case helpers --------------------------------------------------
1830 AppCacheServiceImpl* service() {
1831 return service_.get();
1834 AppCacheStorageImpl* storage() {
1835 return static_cast<AppCacheStorageImpl*>(service()->storage());
1838 AppCacheDatabase* database() {
1839 return storage()->database_;
1842 MockStorageDelegate* delegate() {
1843 return delegate_.get();
1846 void MakeCacheAndGroup(
1847 const GURL& manifest_url, int64 group_id, int64 cache_id,
1848 bool add_to_database) {
1849 AppCacheEntry default_entry(
1850 AppCacheEntry::EXPLICIT, cache_id + kDefaultEntryIdOffset,
1851 kDefaultEntrySize);
1852 group_ = new AppCacheGroup(storage(), manifest_url, group_id);
1853 cache_ = new AppCache(storage(), cache_id);
1854 cache_->AddEntry(kDefaultEntryUrl, default_entry);
1855 cache_->set_complete(true);
1856 group_->AddCache(cache_.get());
1857 if (add_to_database) {
1858 AppCacheDatabase::GroupRecord group_record;
1859 group_record.group_id = group_id;
1860 group_record.manifest_url = manifest_url;
1861 group_record.origin = manifest_url.GetOrigin();
1862 EXPECT_TRUE(database()->InsertGroup(&group_record));
1863 AppCacheDatabase::CacheRecord cache_record;
1864 cache_record.cache_id = cache_id;
1865 cache_record.group_id = group_id;
1866 cache_record.online_wildcard = false;
1867 cache_record.update_time = kZeroTime;
1868 cache_record.cache_size = kDefaultEntrySize;
1869 EXPECT_TRUE(database()->InsertCache(&cache_record));
1870 AppCacheDatabase::EntryRecord entry_record;
1871 entry_record.cache_id = cache_id;
1872 entry_record.url = kDefaultEntryUrl;
1873 entry_record.flags = default_entry.types();
1874 entry_record.response_id = default_entry.response_id();
1875 entry_record.response_size = default_entry.response_size();
1876 EXPECT_TRUE(database()->InsertEntry(&entry_record));
1878 storage()->usage_map_[manifest_url.GetOrigin()] =
1879 default_entry.response_size();
1883 // Data members --------------------------------------------------
1885 scoped_ptr<base::WaitableEvent> test_finished_event_;
1886 std::stack<base::Closure> task_stack_;
1887 scoped_ptr<AppCacheServiceImpl> service_;
1888 scoped_ptr<MockStorageDelegate> delegate_;
1889 scoped_refptr<MockQuotaManagerProxy> mock_quota_manager_proxy_;
1890 scoped_refptr<AppCacheGroup> group_;
1891 scoped_refptr<AppCache> cache_;
1892 scoped_refptr<AppCache> cache2_;
1894 // Specifically for the Reinitalize test.
1895 base::ScopedTempDir temp_directory_;
1896 scoped_ptr<MockServiceObserver> observer_;
1897 MockAppCacheFrontend frontend_;
1898 scoped_ptr<AppCacheBackendImpl> backend_;
1899 scoped_ptr<net::URLRequest> request_;
1903 TEST_F(AppCacheStorageImplTest, LoadCache_Miss) {
1904 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss);
1907 TEST_F(AppCacheStorageImplTest, LoadCache_NearHit) {
1908 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit);
1911 TEST_F(AppCacheStorageImplTest, CreateGroupInEmptyOrigin) {
1912 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin);
1915 TEST_F(AppCacheStorageImplTest, CreateGroupInPopulatedOrigin) {
1916 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin);
1919 TEST_F(AppCacheStorageImplTest, LoadGroupAndCache_FarHit) {
1920 RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit);
1923 TEST_F(AppCacheStorageImplTest, StoreNewGroup) {
1924 RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup);
1927 TEST_F(AppCacheStorageImplTest, StoreExistingGroup) {
1928 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup);
1931 TEST_F(AppCacheStorageImplTest, StoreExistingGroupExistingCache) {
1932 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache);
1935 TEST_F(AppCacheStorageImplTest, FailStoreGroup) {
1936 RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup);
1939 TEST_F(AppCacheStorageImplTest, MakeGroupObsolete) {
1940 RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete);
1943 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeign) {
1944 RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign);
1947 TEST_F(AppCacheStorageImplTest, MarkEntryAsForeignWithLoadInProgress) {
1948 RunTestOnIOThread(
1949 &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress);
1952 TEST_F(AppCacheStorageImplTest, FindNoMainResponse) {
1953 RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse);
1956 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInDatabase) {
1957 RunTestOnIOThread(
1958 &AppCacheStorageImplTest::BasicFindMainResponseInDatabase);
1961 TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) {
1962 RunTestOnIOThread(
1963 &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet);
1966 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) {
1967 RunTestOnIOThread(
1968 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase);
1971 TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInWorkingSet) {
1972 RunTestOnIOThread(
1973 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet);
1976 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInDatabase) {
1977 RunTestOnIOThread(
1978 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase);
1981 TEST_F(AppCacheStorageImplTest, BasicFindMainInterceptResponseInWorkingSet) {
1982 RunTestOnIOThread(
1983 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet);
1986 TEST_F(AppCacheStorageImplTest, FindMainResponseWithMultipleHits) {
1987 RunTestOnIOThread(
1988 &AppCacheStorageImplTest::FindMainResponseWithMultipleHits);
1991 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInDatabase) {
1992 RunTestOnIOThread(
1993 &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase);
1996 TEST_F(AppCacheStorageImplTest, FindMainResponseExclusionsInWorkingSet) {
1997 RunTestOnIOThread(
1998 &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet);
2001 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInWorkingSet) {
2002 RunTestOnIOThread(
2003 &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet);
2006 TEST_F(AppCacheStorageImplTest, FindInterceptPatternMatchInDatabase) {
2007 RunTestOnIOThread(
2008 &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase);
2011 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInWorkingSet) {
2012 RunTestOnIOThread(
2013 &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet);
2016 TEST_F(AppCacheStorageImplTest, FindFallbackPatternMatchInDatabase) {
2017 RunTestOnIOThread(
2018 &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase);
2021 TEST_F(AppCacheStorageImplTest, Reinitialize1) {
2022 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1);
2025 TEST_F(AppCacheStorageImplTest, Reinitialize2) {
2026 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2);
2029 TEST_F(AppCacheStorageImplTest, Reinitialize3) {
2030 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize3);
2033 // That's all folks!
2035 } // namespace content