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.
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"
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
{
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);
97 static void GetMockResponse(const std::string
& path
,
100 const char manifest_headers
[] =
102 "Content-type: text/cache-manifest\0"
104 const char page_headers
[] =
106 "Content-type: text/html\0"
108 const char not_found_headers
[] =
109 "HTTP/1.1 404 NOT FOUND\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
));
119 (*headers
) = std::string(not_found_headers
,
120 arraysize(not_found_headers
));
126 class MockHttpServerJobFactory
127 : public net::URLRequestJobFactory::ProtocolHandler
{
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
);
142 return MockHttpServer::CreateJob(request
, network_delegate
);
145 scoped_ptr
<net::URLRequestInterceptor
> appcache_start_interceptor_
;
148 class IOThread
: public base::Thread
{
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(
165 new MockHttpServerJobFactory(
166 AppCacheInterceptor::CreateStartInterceptor()));
167 job_factory_
= factory
.Pass();
168 request_context_
.reset(new net::TestURLRequestContext());
169 request_context_
->set_job_factory(job_factory_
.get());
170 AppCacheInterceptor::EnsureRegistered();
173 void CleanUp() override
{
174 request_context_
.reset();
175 job_factory_
.reset();
179 scoped_ptr
<net::URLRequestJobFactory
> job_factory_
;
180 scoped_ptr
<net::URLRequestContext
> request_context_
;
183 scoped_ptr
<IOThread
> io_thread
;
184 scoped_ptr
<base::Thread
> db_thread
;
188 class AppCacheStorageImplTest
: public testing::Test
{
190 class MockStorageDelegate
: public AppCacheStorage::Delegate
{
192 explicit MockStorageDelegate(AppCacheStorageImplTest
* test
)
193 : loaded_cache_id_(0), stored_group_success_(false),
194 would_exceed_quota_(false), obsoleted_success_(false),
195 found_cache_id_(kAppCacheNoCacheId
), test_(test
) {
198 void OnCacheLoaded(AppCache
* cache
, int64 cache_id
) override
{
199 loaded_cache_
= cache
;
200 loaded_cache_id_
= cache_id
;
201 test_
->ScheduleNextTask();
204 void OnGroupLoaded(AppCacheGroup
* group
,
205 const GURL
& manifest_url
) override
{
206 loaded_group_
= group
;
207 loaded_manifest_url_
= manifest_url
;
208 loaded_groups_newest_cache_
= group
? group
->newest_complete_cache()
210 test_
->ScheduleNextTask();
213 void OnGroupAndNewestCacheStored(AppCacheGroup
* group
,
214 AppCache
* newest_cache
,
216 bool would_exceed_quota
) override
{
217 stored_group_
= group
;
218 stored_group_success_
= success
;
219 would_exceed_quota_
= would_exceed_quota
;
220 test_
->ScheduleNextTask();
223 void OnGroupMadeObsolete(AppCacheGroup
* group
,
225 int response_code
) override
{
226 obsoleted_group_
= group
;
227 obsoleted_success_
= success
;
228 test_
->ScheduleNextTask();
231 void OnMainResponseFound(const GURL
& url
,
232 const AppCacheEntry
& entry
,
233 const GURL
& namespace_entry_url
,
234 const AppCacheEntry
& fallback_entry
,
237 const GURL
& manifest_url
) override
{
239 found_entry_
= entry
;
240 found_namespace_entry_url_
= namespace_entry_url
;
241 found_fallback_entry_
= fallback_entry
;
242 found_cache_id_
= cache_id
;
243 found_group_id_
= group_id
;
244 found_manifest_url_
= manifest_url
;
245 test_
->ScheduleNextTask();
248 scoped_refptr
<AppCache
> loaded_cache_
;
249 int64 loaded_cache_id_
;
250 scoped_refptr
<AppCacheGroup
> loaded_group_
;
251 GURL loaded_manifest_url_
;
252 scoped_refptr
<AppCache
> loaded_groups_newest_cache_
;
253 scoped_refptr
<AppCacheGroup
> stored_group_
;
254 bool stored_group_success_
;
255 bool would_exceed_quota_
;
256 scoped_refptr
<AppCacheGroup
> obsoleted_group_
;
257 bool obsoleted_success_
;
259 AppCacheEntry found_entry_
;
260 GURL found_namespace_entry_url_
;
261 AppCacheEntry found_fallback_entry_
;
262 int64 found_cache_id_
;
263 int64 found_group_id_
;
264 GURL found_manifest_url_
;
265 AppCacheStorageImplTest
* test_
;
268 class MockQuotaManager
: public storage::QuotaManager
{
271 : QuotaManager(true /* is_incognito */,
273 io_thread
->message_loop_proxy().get(),
274 db_thread
->message_loop_proxy().get(),
278 void GetUsageAndQuota(const GURL
& origin
,
279 storage::StorageType type
,
280 const GetUsageAndQuotaCallback
& callback
) override
{
281 EXPECT_EQ(storage::kStorageTypeTemporary
, type
);
283 base::MessageLoop::current()->PostTask(
285 base::Bind(&MockQuotaManager::CallCallback
,
286 base::Unretained(this),
290 CallCallback(callback
);
293 void CallCallback(const GetUsageAndQuotaCallback
& callback
) {
294 callback
.Run(storage::kQuotaStatusOk
, 0, kMockQuota
);
300 ~MockQuotaManager() override
{}
303 class MockQuotaManagerProxy
: public storage::QuotaManagerProxy
{
305 MockQuotaManagerProxy()
306 : QuotaManagerProxy(NULL
, NULL
),
307 notify_storage_accessed_count_(0),
308 notify_storage_modified_count_(0),
310 mock_manager_(new MockQuotaManager
) {
311 manager_
= mock_manager_
.get();
314 void NotifyStorageAccessed(storage::QuotaClient::ID client_id
,
316 storage::StorageType type
) override
{
317 EXPECT_EQ(storage::QuotaClient::kAppcache
, client_id
);
318 EXPECT_EQ(storage::kStorageTypeTemporary
, type
);
319 ++notify_storage_accessed_count_
;
320 last_origin_
= origin
;
323 void NotifyStorageModified(storage::QuotaClient::ID client_id
,
325 storage::StorageType type
,
326 int64 delta
) override
{
327 EXPECT_EQ(storage::QuotaClient::kAppcache
, client_id
);
328 EXPECT_EQ(storage::kStorageTypeTemporary
, type
);
329 ++notify_storage_modified_count_
;
330 last_origin_
= origin
;
334 // Not needed for our tests.
335 void RegisterClient(storage::QuotaClient
* client
) override
{}
336 void NotifyOriginInUse(const GURL
& origin
) override
{}
337 void NotifyOriginNoLongerInUse(const GURL
& origin
) override
{}
338 void SetUsageCacheEnabled(storage::QuotaClient::ID client_id
,
340 storage::StorageType type
,
341 bool enabled
) override
{}
342 void GetUsageAndQuota(base::SequencedTaskRunner
* original_task_runner
,
344 storage::StorageType type
,
345 const GetUsageAndQuotaCallback
& callback
) override
{}
347 int notify_storage_accessed_count_
;
348 int notify_storage_modified_count_
;
351 scoped_refptr
<MockQuotaManager
> mock_manager_
;
354 ~MockQuotaManagerProxy() override
{}
357 template <class Method
>
358 void RunMethod(Method method
) {
362 // Helper callback to run a test on our io_thread. The io_thread is spun up
363 // once and reused for all tests.
364 template <class Method
>
365 void MethodWrapper(Method method
) {
368 // Ensure InitTask execution prior to conducting a test.
369 FlushDbThreadTasks();
371 // We also have to wait for InitTask completion call to be performed
372 // on the IO thread prior to running the test. Its guaranteed to be
373 // queued by this time.
374 base::MessageLoop::current()->PostTask(
376 base::Bind(&AppCacheStorageImplTest::RunMethod
<Method
>,
377 base::Unretained(this),
381 static void SetUpTestCase() {
382 // We start both threads as TYPE_IO because we also use the db_thead
383 // for the disk_cache which needs to be of TYPE_IO.
384 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
385 io_thread
.reset(new IOThread("AppCacheTest.IOThread"));
386 ASSERT_TRUE(io_thread
->StartWithOptions(options
));
387 db_thread
.reset(new base::Thread("AppCacheTest::DBThread"));
388 ASSERT_TRUE(db_thread
->StartWithOptions(options
));
391 static void TearDownTestCase() {
392 io_thread
.reset(NULL
);
393 db_thread
.reset(NULL
);
396 // Test harness --------------------------------------------------
398 AppCacheStorageImplTest() {
401 template <class Method
>
402 void RunTestOnIOThread(Method method
) {
403 test_finished_event_
.reset(new base::WaitableEvent(false, false));
404 io_thread
->message_loop()->PostTask(
405 FROM_HERE
, base::Bind(&AppCacheStorageImplTest::MethodWrapper
<Method
>,
406 base::Unretained(this), method
));
407 test_finished_event_
->Wait();
411 DCHECK(base::MessageLoop::current() == io_thread
->message_loop());
412 service_
.reset(new AppCacheServiceImpl(NULL
));
413 service_
->Initialize(base::FilePath(), db_thread
->task_runner(), NULL
);
414 mock_quota_manager_proxy_
= new MockQuotaManagerProxy();
415 service_
->quota_manager_proxy_
= mock_quota_manager_proxy_
;
416 delegate_
.reset(new MockStorageDelegate(this));
419 void TearDownTest() {
420 DCHECK(base::MessageLoop::current() == io_thread
->message_loop());
421 storage()->CancelDelegateCallbacks(delegate());
425 mock_quota_manager_proxy_
= NULL
;
428 FlushDbThreadTasks();
431 void TestFinished() {
432 // We unwind the stack prior to finishing up to let stack
433 // based objects get deleted.
434 DCHECK(base::MessageLoop::current() == io_thread
->message_loop());
435 base::MessageLoop::current()->PostTask(
437 base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound
,
438 base::Unretained(this)));
441 void TestFinishedUnwound() {
443 test_finished_event_
->Signal();
446 void PushNextTask(const base::Closure
& task
) {
447 task_stack_
.push(task
);
450 void ScheduleNextTask() {
451 DCHECK(base::MessageLoop::current() == io_thread
->message_loop());
452 if (task_stack_
.empty()) {
455 base::MessageLoop::current()->PostTask(FROM_HERE
, task_stack_
.top());
459 static void SignalEvent(base::WaitableEvent
* event
) {
463 void FlushDbThreadTasks() {
464 // We pump a task thru the db thread to ensure any tasks previously
465 // scheduled on that thread have been performed prior to return.
466 base::WaitableEvent
event(false, false);
467 db_thread
->message_loop()->PostTask(
468 FROM_HERE
, base::Bind(&AppCacheStorageImplTest::SignalEvent
, &event
));
472 // LoadCache_Miss ----------------------------------------------------
474 void LoadCache_Miss() {
475 // Attempt to load a cache that doesn't exist. Should
476 // complete asynchronously.
477 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Miss
,
478 base::Unretained(this)));
480 storage()->LoadCache(111, delegate());
481 EXPECT_NE(111, delegate()->loaded_cache_id_
);
484 void Verify_LoadCache_Miss() {
485 EXPECT_EQ(111, delegate()->loaded_cache_id_
);
486 EXPECT_FALSE(delegate()->loaded_cache_
.get());
487 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
488 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
492 // LoadCache_NearHit -------------------------------------------------
494 void LoadCache_NearHit() {
495 // Attempt to load a cache that is currently in use
496 // and does not require loading from storage. This
497 // load should complete syncly.
499 // Setup some preconditions. Make an 'unstored' cache for
500 // us to load. The ctor should put it in the working set.
501 int64 cache_id
= storage()->NewCacheId();
502 scoped_refptr
<AppCache
> cache(new AppCache(storage(), cache_id
));
505 storage()->LoadCache(cache_id
, delegate());
506 EXPECT_EQ(cache_id
, delegate()->loaded_cache_id_
);
507 EXPECT_EQ(cache
.get(), delegate()->loaded_cache_
.get());
508 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
509 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
513 // CreateGroup --------------------------------------------
515 void CreateGroupInEmptyOrigin() {
516 // Attempt to load a group that doesn't exist, one should
517 // be created for us, but not stored.
519 // Since the origin has no groups, the storage class will respond
521 storage()->LoadOrCreateGroup(kManifestUrl
, delegate());
522 Verify_CreateGroup();
525 void CreateGroupInPopulatedOrigin() {
526 // Attempt to load a group that doesn't exist, one should
527 // be created for us, but not stored.
528 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_CreateGroup
,
529 base::Unretained(this)));
531 // Since the origin has groups, storage class will have to
532 // consult the database and completion will be async.
533 storage()->usage_map_
[kOrigin
] = kDefaultEntrySize
;
535 storage()->LoadOrCreateGroup(kManifestUrl
, delegate());
536 EXPECT_FALSE(delegate()->loaded_group_
.get());
539 void Verify_CreateGroup() {
540 EXPECT_EQ(kManifestUrl
, delegate()->loaded_manifest_url_
);
541 EXPECT_TRUE(delegate()->loaded_group_
.get());
542 EXPECT_TRUE(delegate()->loaded_group_
->HasOneRef());
543 EXPECT_FALSE(delegate()->loaded_group_
->newest_complete_cache());
545 // Should not have been stored in the database.
546 AppCacheDatabase::GroupRecord record
;
547 EXPECT_FALSE(database()->FindGroup(
548 delegate()->loaded_group_
->group_id(), &record
));
550 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
551 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
556 // LoadGroupAndCache_FarHit --------------------------------------
558 void LoadGroupAndCache_FarHit() {
559 // Attempt to load a cache that is not currently in use
560 // and does require loading from disk. This
561 // load should complete asynchronously.
562 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Far_Hit
,
563 base::Unretained(this)));
565 // Setup some preconditions. Create a group and newest cache that
566 // appear to be "stored" and "not currently in use".
567 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
571 // Conduct the cache load test, completes async
572 storage()->LoadCache(1, delegate());
575 void Verify_LoadCache_Far_Hit() {
576 EXPECT_TRUE(delegate()->loaded_cache_
.get());
577 EXPECT_TRUE(delegate()->loaded_cache_
->HasOneRef());
578 EXPECT_EQ(1, delegate()->loaded_cache_id_
);
580 // The group should also have been loaded.
581 EXPECT_TRUE(delegate()->loaded_cache_
->owning_group());
582 EXPECT_TRUE(delegate()->loaded_cache_
->owning_group()->HasOneRef());
583 EXPECT_EQ(1, delegate()->loaded_cache_
->owning_group()->group_id());
585 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
586 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
588 // Drop things from the working set.
589 delegate()->loaded_cache_
= NULL
;
590 EXPECT_FALSE(delegate()->loaded_group_
.get());
592 // Conduct the group load test, also complete asynchronously.
593 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit
,
594 base::Unretained(this)));
596 storage()->LoadOrCreateGroup(kManifestUrl
, delegate());
599 void Verify_LoadGroup_Far_Hit() {
600 EXPECT_TRUE(delegate()->loaded_group_
.get());
601 EXPECT_EQ(kManifestUrl
, delegate()->loaded_manifest_url_
);
602 EXPECT_TRUE(delegate()->loaded_group_
->newest_complete_cache());
603 delegate()->loaded_groups_newest_cache_
= NULL
;
604 EXPECT_TRUE(delegate()->loaded_group_
->HasOneRef());
605 EXPECT_EQ(2, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
606 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
610 // StoreNewGroup --------------------------------------
612 void StoreNewGroup() {
613 // Store a group and its newest cache. Should complete asynchronously.
614 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreNewGroup
,
615 base::Unretained(this)));
617 // Setup some preconditions. Create a group and newest cache that
618 // appear to be "unstored".
619 group_
= new AppCacheGroup(
620 storage(), kManifestUrl
, storage()->NewGroupId());
621 cache_
= new AppCache(storage(), storage()->NewCacheId());
622 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::EXPLICIT
, 1,
624 // Hold a ref to the cache simulate the UpdateJob holding that ref,
625 // and hold a ref to the group to simulate the CacheHost holding that ref.
627 // Have the quota manager retrun asynchronously for this test.
628 mock_quota_manager_proxy_
->mock_manager_
->async_
= true;
630 // Conduct the store test.
631 storage()->StoreGroupAndNewestCache(group_
.get(), cache_
.get(), delegate());
632 EXPECT_FALSE(delegate()->stored_group_success_
);
635 void Verify_StoreNewGroup() {
636 EXPECT_TRUE(delegate()->stored_group_success_
);
637 EXPECT_EQ(group_
.get(), delegate()->stored_group_
.get());
638 EXPECT_EQ(cache_
.get(), group_
->newest_complete_cache());
639 EXPECT_TRUE(cache_
->is_complete());
641 // Should have been stored in the database.
642 AppCacheDatabase::GroupRecord group_record
;
643 AppCacheDatabase::CacheRecord cache_record
;
644 EXPECT_TRUE(database()->FindGroup(group_
->group_id(), &group_record
));
645 EXPECT_TRUE(database()->FindCache(cache_
->cache_id(), &cache_record
));
647 // Verify quota bookkeeping
648 EXPECT_EQ(kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
649 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
650 EXPECT_EQ(kOrigin
, mock_quota_manager_proxy_
->last_origin_
);
651 EXPECT_EQ(kDefaultEntrySize
, mock_quota_manager_proxy_
->last_delta_
);
656 // StoreExistingGroup --------------------------------------
658 void StoreExistingGroup() {
659 // Store a group and its newest cache. Should complete asynchronously.
660 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreExistingGroup
,
661 base::Unretained(this)));
663 // Setup some preconditions. Create a group and old complete cache
664 // that appear to be "stored"
665 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
666 EXPECT_EQ(kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
668 // And a newest unstored complete cache.
669 cache2_
= new AppCache(storage(), 2);
670 cache2_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::MASTER
, 1,
671 kDefaultEntrySize
+ 100));
674 storage()->StoreGroupAndNewestCache(
675 group_
.get(), cache2_
.get(), delegate());
676 EXPECT_FALSE(delegate()->stored_group_success_
);
679 void Verify_StoreExistingGroup() {
680 EXPECT_TRUE(delegate()->stored_group_success_
);
681 EXPECT_EQ(group_
.get(), delegate()->stored_group_
.get());
682 EXPECT_EQ(cache2_
.get(), group_
->newest_complete_cache());
683 EXPECT_TRUE(cache2_
->is_complete());
685 // The new cache should have been stored in the database.
686 AppCacheDatabase::GroupRecord group_record
;
687 AppCacheDatabase::CacheRecord cache_record
;
688 EXPECT_TRUE(database()->FindGroup(1, &group_record
));
689 EXPECT_TRUE(database()->FindCache(2, &cache_record
));
691 // The old cache should have been deleted
692 EXPECT_FALSE(database()->FindCache(1, &cache_record
));
694 // Verify quota bookkeeping
695 EXPECT_EQ(kDefaultEntrySize
+ 100, storage()->usage_map_
[kOrigin
]);
696 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
697 EXPECT_EQ(kOrigin
, mock_quota_manager_proxy_
->last_origin_
);
698 EXPECT_EQ(100, mock_quota_manager_proxy_
->last_delta_
);
703 // StoreExistingGroupExistingCache -------------------------------
705 void StoreExistingGroupExistingCache() {
706 // Store a group with updates to its existing newest complete cache.
707 // Setup some preconditions. Create a group and a complete cache that
708 // appear to be "stored".
710 // Setup some preconditions. Create a group and old complete cache
711 // that appear to be "stored"
712 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
713 EXPECT_EQ(kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
716 base::Time now
= base::Time::Now();
717 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::MASTER
, 1, 100));
718 cache_
->set_update_time(now
);
720 PushNextTask(base::Bind(
721 &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache
,
722 base::Unretained(this), now
));
725 EXPECT_EQ(cache_
.get(), group_
->newest_complete_cache());
726 storage()->StoreGroupAndNewestCache(group_
.get(), cache_
.get(), delegate());
727 EXPECT_FALSE(delegate()->stored_group_success_
);
730 void Verify_StoreExistingGroupExistingCache(
731 base::Time expected_update_time
) {
732 EXPECT_TRUE(delegate()->stored_group_success_
);
733 EXPECT_EQ(cache_
.get(), group_
->newest_complete_cache());
735 AppCacheDatabase::CacheRecord cache_record
;
736 EXPECT_TRUE(database()->FindCache(1, &cache_record
));
737 EXPECT_EQ(1, cache_record
.cache_id
);
738 EXPECT_EQ(1, cache_record
.group_id
);
739 EXPECT_FALSE(cache_record
.online_wildcard
);
740 EXPECT_TRUE(expected_update_time
== cache_record
.update_time
);
741 EXPECT_EQ(100 + kDefaultEntrySize
, cache_record
.cache_size
);
743 std::vector
<AppCacheDatabase::EntryRecord
> entry_records
;
744 EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records
));
745 EXPECT_EQ(2U, entry_records
.size());
746 if (entry_records
[0].url
== kDefaultEntryUrl
)
747 entry_records
.erase(entry_records
.begin());
748 EXPECT_EQ(1 , entry_records
[0].cache_id
);
749 EXPECT_EQ(kEntryUrl
, entry_records
[0].url
);
750 EXPECT_EQ(AppCacheEntry::MASTER
, entry_records
[0].flags
);
751 EXPECT_EQ(1, entry_records
[0].response_id
);
752 EXPECT_EQ(100, entry_records
[0].response_size
);
754 // Verify quota bookkeeping
755 EXPECT_EQ(100 + kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
756 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
757 EXPECT_EQ(kOrigin
, mock_quota_manager_proxy_
->last_origin_
);
758 EXPECT_EQ(100, mock_quota_manager_proxy_
->last_delta_
);
763 // FailStoreGroup --------------------------------------
765 void FailStoreGroup() {
766 // Store a group and its newest cache. Should complete asynchronously.
767 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FailStoreGroup
,
768 base::Unretained(this)));
770 // Setup some preconditions. Create a group and newest cache that
771 // appear to be "unstored" and big enough to exceed the 5M limit.
772 const int64 kTooBig
= 10 * 1024 * 1024; // 10M
773 group_
= new AppCacheGroup(
774 storage(), kManifestUrl
, storage()->NewGroupId());
775 cache_
= new AppCache(storage(), storage()->NewCacheId());
776 cache_
->AddEntry(kManifestUrl
,
777 AppCacheEntry(AppCacheEntry::MANIFEST
, 1, kTooBig
));
778 // Hold a ref to the cache simulate the UpdateJob holding that ref,
779 // and hold a ref to the group to simulate the CacheHost holding that ref.
781 // Conduct the store test.
782 storage()->StoreGroupAndNewestCache(group_
.get(), cache_
.get(), delegate());
783 EXPECT_FALSE(delegate()->stored_group_success_
); // Expected to be async.
786 void Verify_FailStoreGroup() {
787 EXPECT_FALSE(delegate()->stored_group_success_
);
788 EXPECT_TRUE(delegate()->would_exceed_quota_
);
790 // Should not have been stored in the database.
791 AppCacheDatabase::GroupRecord group_record
;
792 AppCacheDatabase::CacheRecord cache_record
;
793 EXPECT_FALSE(database()->FindGroup(group_
->group_id(), &group_record
));
794 EXPECT_FALSE(database()->FindCache(cache_
->cache_id(), &cache_record
));
796 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
797 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
802 // MakeGroupObsolete -------------------------------
804 void MakeGroupObsolete() {
805 // Make a group obsolete, should complete asynchronously.
806 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete
,
807 base::Unretained(this)));
809 // Setup some preconditions. Create a group and newest cache that
810 // appears to be "stored" and "currently in use".
811 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
812 EXPECT_EQ(kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
814 // Also insert some related records.
815 AppCacheDatabase::EntryRecord entry_record
;
816 entry_record
.cache_id
= 1;
817 entry_record
.flags
= AppCacheEntry::FALLBACK
;
818 entry_record
.response_id
= 1;
819 entry_record
.url
= kEntryUrl
;
820 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
822 AppCacheDatabase::NamespaceRecord fallback_namespace_record
;
823 fallback_namespace_record
.cache_id
= 1;
824 fallback_namespace_record
.namespace_
.target_url
= kEntryUrl
;
825 fallback_namespace_record
.namespace_
.namespace_url
= kFallbackNamespace
;
826 fallback_namespace_record
.origin
= kManifestUrl
.GetOrigin();
827 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record
));
829 AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record
;
830 online_whitelist_record
.cache_id
= 1;
831 online_whitelist_record
.namespace_url
= kOnlineNamespace
;
832 EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record
));
835 storage()->MakeGroupObsolete(group_
.get(), delegate(), 0);
836 EXPECT_FALSE(group_
->is_obsolete());
839 void Verify_MakeGroupObsolete() {
840 EXPECT_TRUE(delegate()->obsoleted_success_
);
841 EXPECT_EQ(group_
.get(), delegate()->obsoleted_group_
.get());
842 EXPECT_TRUE(group_
->is_obsolete());
843 EXPECT_TRUE(storage()->usage_map_
.empty());
845 // The cache and group have been deleted from the database.
846 AppCacheDatabase::GroupRecord group_record
;
847 AppCacheDatabase::CacheRecord cache_record
;
848 EXPECT_FALSE(database()->FindGroup(1, &group_record
));
849 EXPECT_FALSE(database()->FindCache(1, &cache_record
));
851 // The related records should have been deleted too.
852 std::vector
<AppCacheDatabase::EntryRecord
> entry_records
;
853 database()->FindEntriesForCache(1, &entry_records
);
854 EXPECT_TRUE(entry_records
.empty());
855 std::vector
<AppCacheDatabase::NamespaceRecord
> intercept_records
;
856 std::vector
<AppCacheDatabase::NamespaceRecord
> fallback_records
;
857 database()->FindNamespacesForCache(
858 1, &intercept_records
, &fallback_records
);
859 EXPECT_TRUE(fallback_records
.empty());
860 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelist_records
;
861 database()->FindOnlineWhiteListForCache(1, &whitelist_records
);
862 EXPECT_TRUE(whitelist_records
.empty());
864 // Verify quota bookkeeping
865 EXPECT_TRUE(storage()->usage_map_
.empty());
866 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
867 EXPECT_EQ(kOrigin
, mock_quota_manager_proxy_
->last_origin_
);
868 EXPECT_EQ(-kDefaultEntrySize
, mock_quota_manager_proxy_
->last_delta_
);
873 // MarkEntryAsForeign -------------------------------
875 void MarkEntryAsForeign() {
876 // Setup some preconditions. Create a cache with an entry
877 // in storage and in the working set.
878 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
879 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::EXPLICIT
));
880 AppCacheDatabase::EntryRecord entry_record
;
881 entry_record
.cache_id
= 1;
882 entry_record
.url
= kEntryUrl
;
883 entry_record
.flags
= AppCacheEntry::EXPLICIT
;
884 entry_record
.response_id
= 0;
885 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
886 EXPECT_FALSE(cache_
->GetEntry(kEntryUrl
)->IsForeign());
889 storage()->MarkEntryAsForeign(kEntryUrl
, 1);
891 // The entry in the working set should have been updated syncly.
892 EXPECT_TRUE(cache_
->GetEntry(kEntryUrl
)->IsForeign());
893 EXPECT_TRUE(cache_
->GetEntry(kEntryUrl
)->IsExplicit());
895 // And the entry in storage should also be updated, but that
896 // happens asynchronously on the db thread.
897 FlushDbThreadTasks();
898 AppCacheDatabase::EntryRecord entry_record2
;
899 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl
, &entry_record2
));
900 EXPECT_EQ(AppCacheEntry::EXPLICIT
| AppCacheEntry::FOREIGN
,
901 entry_record2
.flags
);
905 // MarkEntryAsForeignWithLoadInProgress -------------------------------
907 void MarkEntryAsForeignWithLoadInProgress() {
908 PushNextTask(base::Bind(
909 &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress
,
910 base::Unretained(this)));
912 // Setup some preconditions. Create a cache with an entry
913 // in storage, but not in the working set.
914 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
915 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::EXPLICIT
));
916 AppCacheDatabase::EntryRecord entry_record
;
917 entry_record
.cache_id
= 1;
918 entry_record
.url
= kEntryUrl
;
919 entry_record
.flags
= AppCacheEntry::EXPLICIT
;
920 entry_record
.response_id
= 0;
921 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
922 EXPECT_FALSE(cache_
->GetEntry(kEntryUrl
)->IsForeign());
923 EXPECT_TRUE(cache_
->HasOneRef());
927 // Conduct the test, start a cache load, and prior to completion
928 // of that load, mark the entry as foreign.
929 storage()->LoadCache(1, delegate());
930 storage()->MarkEntryAsForeign(kEntryUrl
, 1);
933 void Verify_MarkEntryAsForeignWithLoadInProgress() {
934 EXPECT_EQ(1, delegate()->loaded_cache_id_
);
935 EXPECT_TRUE(delegate()->loaded_cache_
.get());
937 // The entry in the working set should have been updated upon load.
938 EXPECT_TRUE(delegate()->loaded_cache_
->GetEntry(kEntryUrl
)->IsForeign());
939 EXPECT_TRUE(delegate()->loaded_cache_
->GetEntry(kEntryUrl
)->IsExplicit());
941 // And the entry in storage should also be updated.
942 FlushDbThreadTasks();
943 AppCacheDatabase::EntryRecord entry_record
;
944 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl
, &entry_record
));
945 EXPECT_EQ(AppCacheEntry::EXPLICIT
| AppCacheEntry::FOREIGN
,
950 // FindNoMainResponse -------------------------------
952 void FindNoMainResponse() {
953 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse
,
954 base::Unretained(this)));
957 storage()->FindResponseForMainRequest(kEntryUrl
, GURL(), delegate());
958 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
961 void Verify_FindNoMainResponse() {
962 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
963 EXPECT_TRUE(delegate()->found_manifest_url_
.is_empty());
964 EXPECT_EQ(kAppCacheNoCacheId
, delegate()->found_cache_id_
);
965 EXPECT_EQ(kAppCacheNoResponseId
, delegate()->found_entry_
.response_id());
966 EXPECT_EQ(kAppCacheNoResponseId
,
967 delegate()->found_fallback_entry_
.response_id());
968 EXPECT_TRUE(delegate()->found_namespace_entry_url_
.is_empty());
969 EXPECT_EQ(0, delegate()->found_entry_
.types());
970 EXPECT_EQ(0, delegate()->found_fallback_entry_
.types());
974 // BasicFindMainResponse -------------------------------
976 void BasicFindMainResponseInDatabase() {
977 BasicFindMainResponse(true);
980 void BasicFindMainResponseInWorkingSet() {
981 BasicFindMainResponse(false);
984 void BasicFindMainResponse(bool drop_from_working_set
) {
985 PushNextTask(base::Bind(
986 &AppCacheStorageImplTest::Verify_BasicFindMainResponse
,
987 base::Unretained(this)));
989 // Setup some preconditions. Create a complete cache with an entry
991 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
992 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::EXPLICIT
, 1));
993 AppCacheDatabase::EntryRecord entry_record
;
994 entry_record
.cache_id
= 1;
995 entry_record
.url
= kEntryUrl
;
996 entry_record
.flags
= AppCacheEntry::EXPLICIT
;
997 entry_record
.response_id
= 1;
998 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1000 // Optionally drop the cache/group pair from the working set.
1001 if (drop_from_working_set
) {
1002 EXPECT_TRUE(cache_
->HasOneRef());
1004 EXPECT_TRUE(group_
->HasOneRef());
1008 // Conduct the test.
1009 storage()->FindResponseForMainRequest(kEntryUrl
, GURL(), delegate());
1010 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
1013 void Verify_BasicFindMainResponse() {
1014 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
1015 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1016 EXPECT_EQ(1, delegate()->found_cache_id_
);
1017 EXPECT_EQ(2, delegate()->found_group_id_
);
1018 EXPECT_EQ(1, delegate()->found_entry_
.response_id());
1019 EXPECT_TRUE(delegate()->found_entry_
.IsExplicit());
1020 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1024 // BasicFindMainFallbackResponse -------------------------------
1026 void BasicFindMainFallbackResponseInDatabase() {
1027 BasicFindMainFallbackResponse(true);
1030 void BasicFindMainFallbackResponseInWorkingSet() {
1031 BasicFindMainFallbackResponse(false);
1034 void BasicFindMainFallbackResponse(bool drop_from_working_set
) {
1035 PushNextTask(base::Bind(
1036 &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse
,
1037 base::Unretained(this)));
1039 // Setup some preconditions. Create a complete cache with a
1040 // fallback namespace and entry.
1041 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
1042 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::FALLBACK
, 1));
1043 cache_
->AddEntry(kEntryUrl2
, AppCacheEntry(AppCacheEntry::FALLBACK
, 2));
1044 cache_
->fallback_namespaces_
.push_back(
1045 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1046 kFallbackNamespace2
,
1049 cache_
->fallback_namespaces_
.push_back(
1050 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1054 AppCacheDatabase::CacheRecord cache_record
;
1055 std::vector
<AppCacheDatabase::EntryRecord
> entries
;
1056 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1057 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1058 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1059 cache_
->ToDatabaseRecords(group_
.get(),
1066 std::vector
<AppCacheDatabase::EntryRecord
>::const_iterator iter
=
1068 while (iter
!= entries
.end()) {
1069 // MakeCacheAndGroup has inserted the default entry record already.
1070 if (iter
->url
!= kDefaultEntryUrl
)
1071 EXPECT_TRUE(database()->InsertEntry(&(*iter
)));
1075 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks
));
1076 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists
));
1077 if (drop_from_working_set
) {
1078 EXPECT_TRUE(cache_
->HasOneRef());
1080 EXPECT_TRUE(group_
->HasOneRef());
1084 // Conduct the test. The test url is in both fallback namespace urls,
1085 // but should match the longer of the two.
1086 storage()->FindResponseForMainRequest(kFallbackTestUrl
, GURL(), delegate());
1087 EXPECT_NE(kFallbackTestUrl
, delegate()->found_url_
);
1090 void Verify_BasicFindMainFallbackResponse() {
1091 EXPECT_EQ(kFallbackTestUrl
, delegate()->found_url_
);
1092 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1093 EXPECT_EQ(1, delegate()->found_cache_id_
);
1094 EXPECT_EQ(2, delegate()->found_group_id_
);
1095 EXPECT_FALSE(delegate()->found_entry_
.has_response_id());
1096 EXPECT_EQ(2, delegate()->found_fallback_entry_
.response_id());
1097 EXPECT_EQ(kEntryUrl2
, delegate()->found_namespace_entry_url_
);
1098 EXPECT_TRUE(delegate()->found_fallback_entry_
.IsFallback());
1102 // BasicFindMainInterceptResponse -------------------------------
1104 void BasicFindMainInterceptResponseInDatabase() {
1105 BasicFindMainInterceptResponse(true);
1108 void BasicFindMainInterceptResponseInWorkingSet() {
1109 BasicFindMainInterceptResponse(false);
1112 void BasicFindMainInterceptResponse(bool drop_from_working_set
) {
1113 PushNextTask(base::Bind(
1114 &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse
,
1115 base::Unretained(this)));
1117 // Setup some preconditions. Create a complete cache with an
1118 // intercept namespace and entry.
1119 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
1120 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::INTERCEPT
, 1));
1121 cache_
->AddEntry(kEntryUrl2
, AppCacheEntry(AppCacheEntry::INTERCEPT
, 2));
1122 cache_
->intercept_namespaces_
.push_back(
1123 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE
, kInterceptNamespace2
,
1124 kEntryUrl2
, false));
1125 cache_
->intercept_namespaces_
.push_back(
1126 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE
, kInterceptNamespace
,
1128 AppCacheDatabase::CacheRecord cache_record
;
1129 std::vector
<AppCacheDatabase::EntryRecord
> entries
;
1130 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1131 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1132 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1133 cache_
->ToDatabaseRecords(group_
.get(),
1140 std::vector
<AppCacheDatabase::EntryRecord
>::const_iterator iter
=
1142 while (iter
!= entries
.end()) {
1143 // MakeCacheAndGroup has inserted the default entry record already
1144 if (iter
->url
!= kDefaultEntryUrl
)
1145 EXPECT_TRUE(database()->InsertEntry(&(*iter
)));
1149 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts
));
1150 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists
));
1151 if (drop_from_working_set
) {
1152 EXPECT_TRUE(cache_
->HasOneRef());
1154 EXPECT_TRUE(group_
->HasOneRef());
1158 // Conduct the test. The test url is in both intercept namespaces,
1159 // but should match the longer of the two.
1160 storage()->FindResponseForMainRequest(
1161 kInterceptTestUrl
, GURL(), delegate());
1162 EXPECT_NE(kInterceptTestUrl
, delegate()->found_url_
);
1165 void Verify_BasicFindMainInterceptResponse() {
1166 EXPECT_EQ(kInterceptTestUrl
, delegate()->found_url_
);
1167 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1168 EXPECT_EQ(1, delegate()->found_cache_id_
);
1169 EXPECT_EQ(2, delegate()->found_group_id_
);
1170 EXPECT_EQ(2, delegate()->found_entry_
.response_id());
1171 EXPECT_TRUE(delegate()->found_entry_
.IsIntercept());
1172 EXPECT_EQ(kEntryUrl2
, delegate()->found_namespace_entry_url_
);
1173 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1177 // FindInterceptPatternMatch ----------------------------------------
1179 void FindInterceptPatternMatchInDatabase() {
1180 FindInterceptPatternMatch(true);
1183 void FindInterceptPatternMatchInWorkingSet() {
1184 FindInterceptPatternMatch(false);
1187 void FindInterceptPatternMatch(bool drop_from_working_set
) {
1188 // Setup some preconditions. Create a complete cache with an
1189 // pattern matching intercept namespace and entry.
1190 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
1191 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::INTERCEPT
, 1));
1192 cache_
->intercept_namespaces_
.push_back(
1193 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE
,
1194 kInterceptPatternNamespace
, kEntryUrl
, true));
1195 AppCacheDatabase::CacheRecord cache_record
;
1196 std::vector
<AppCacheDatabase::EntryRecord
> entries
;
1197 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1198 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1199 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1200 cache_
->ToDatabaseRecords(group_
.get(),
1207 std::vector
<AppCacheDatabase::EntryRecord
>::const_iterator iter
=
1209 while (iter
!= entries
.end()) {
1210 // MakeCacheAndGroup has inserted the default entry record already
1211 if (iter
->url
!= kDefaultEntryUrl
)
1212 EXPECT_TRUE(database()->InsertEntry(&(*iter
)));
1216 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts
));
1217 if (drop_from_working_set
) {
1218 EXPECT_TRUE(cache_
->HasOneRef());
1220 EXPECT_TRUE(group_
->HasOneRef());
1224 // First test something that does not match the pattern.
1225 PushNextTask(base::Bind(
1226 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative
,
1227 base::Unretained(this)));
1228 storage()->FindResponseForMainRequest(
1229 kInterceptPatternTestNegativeUrl
, GURL(), delegate());
1230 EXPECT_EQ(GURL(), delegate()->found_url_
); // Is always async.
1233 void Verify_FindInterceptPatternMatchNegative() {
1234 EXPECT_EQ(kInterceptPatternTestNegativeUrl
, delegate()->found_url_
);
1235 EXPECT_TRUE(delegate()->found_manifest_url_
.is_empty());
1236 EXPECT_EQ(kAppCacheNoCacheId
, delegate()->found_cache_id_
);
1237 EXPECT_EQ(kAppCacheNoResponseId
, delegate()->found_entry_
.response_id());
1238 EXPECT_EQ(kAppCacheNoResponseId
,
1239 delegate()->found_fallback_entry_
.response_id());
1240 EXPECT_TRUE(delegate()->found_namespace_entry_url_
.is_empty());
1241 EXPECT_EQ(0, delegate()->found_entry_
.types());
1242 EXPECT_EQ(0, delegate()->found_fallback_entry_
.types());
1244 // Then test something that matches.
1245 PushNextTask(base::Bind(
1246 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive
,
1247 base::Unretained(this)));
1248 storage()->FindResponseForMainRequest(
1249 kInterceptPatternTestPositiveUrl
, GURL(), delegate());
1252 void Verify_FindInterceptPatternMatchPositive() {
1253 EXPECT_EQ(kInterceptPatternTestPositiveUrl
, delegate()->found_url_
);
1254 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1255 EXPECT_EQ(1, delegate()->found_cache_id_
);
1256 EXPECT_EQ(2, delegate()->found_group_id_
);
1257 EXPECT_EQ(1, delegate()->found_entry_
.response_id());
1258 EXPECT_TRUE(delegate()->found_entry_
.IsIntercept());
1259 EXPECT_EQ(kEntryUrl
, delegate()->found_namespace_entry_url_
);
1260 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1264 // FindFallbackPatternMatch -------------------------------
1266 void FindFallbackPatternMatchInDatabase() {
1267 FindFallbackPatternMatch(true);
1270 void FindFallbackPatternMatchInWorkingSet() {
1271 FindFallbackPatternMatch(false);
1274 void FindFallbackPatternMatch(bool drop_from_working_set
) {
1275 // Setup some preconditions. Create a complete cache with a
1276 // pattern matching fallback namespace and entry.
1277 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
1278 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::FALLBACK
, 1));
1279 cache_
->fallback_namespaces_
.push_back(
1280 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1281 kFallbackPatternNamespace
, kEntryUrl
, true));
1282 AppCacheDatabase::CacheRecord cache_record
;
1283 std::vector
<AppCacheDatabase::EntryRecord
> entries
;
1284 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1285 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1286 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1287 cache_
->ToDatabaseRecords(group_
.get(),
1294 std::vector
<AppCacheDatabase::EntryRecord
>::const_iterator iter
=
1296 while (iter
!= entries
.end()) {
1297 // MakeCacheAndGroup has inserted the default entry record already.
1298 if (iter
->url
!= kDefaultEntryUrl
)
1299 EXPECT_TRUE(database()->InsertEntry(&(*iter
)));
1303 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks
));
1304 if (drop_from_working_set
) {
1305 EXPECT_TRUE(cache_
->HasOneRef());
1307 EXPECT_TRUE(group_
->HasOneRef());
1311 // First test something that does not match the pattern.
1312 PushNextTask(base::Bind(
1313 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative
,
1314 base::Unretained(this)));
1315 storage()->FindResponseForMainRequest(
1316 kFallbackPatternTestNegativeUrl
, GURL(), delegate());
1317 EXPECT_EQ(GURL(), delegate()->found_url_
); // Is always async.
1320 void Verify_FindFallbackPatternMatchNegative() {
1321 EXPECT_EQ(kFallbackPatternTestNegativeUrl
, delegate()->found_url_
);
1322 EXPECT_TRUE(delegate()->found_manifest_url_
.is_empty());
1323 EXPECT_EQ(kAppCacheNoCacheId
, delegate()->found_cache_id_
);
1324 EXPECT_EQ(kAppCacheNoResponseId
, delegate()->found_entry_
.response_id());
1325 EXPECT_EQ(kAppCacheNoResponseId
,
1326 delegate()->found_fallback_entry_
.response_id());
1327 EXPECT_TRUE(delegate()->found_namespace_entry_url_
.is_empty());
1328 EXPECT_EQ(0, delegate()->found_entry_
.types());
1329 EXPECT_EQ(0, delegate()->found_fallback_entry_
.types());
1331 // Then test something that matches.
1332 PushNextTask(base::Bind(
1333 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive
,
1334 base::Unretained(this)));
1335 storage()->FindResponseForMainRequest(
1336 kFallbackPatternTestPositiveUrl
, GURL(), delegate());
1339 void Verify_FindFallbackPatternMatchPositive() {
1340 EXPECT_EQ(kFallbackPatternTestPositiveUrl
, delegate()->found_url_
);
1341 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1342 EXPECT_EQ(1, delegate()->found_cache_id_
);
1343 EXPECT_EQ(2, delegate()->found_group_id_
);
1344 EXPECT_EQ(1, delegate()->found_fallback_entry_
.response_id());
1345 EXPECT_TRUE(delegate()->found_fallback_entry_
.IsFallback());
1346 EXPECT_EQ(kEntryUrl
, delegate()->found_namespace_entry_url_
);
1347 EXPECT_FALSE(delegate()->found_entry_
.has_response_id());
1351 // FindMainResponseWithMultipleHits -------------------------------
1353 void FindMainResponseWithMultipleHits() {
1354 PushNextTask(base::Bind(
1355 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits
,
1356 base::Unretained(this)));
1358 // Setup some preconditions, create a few caches with an identical set
1359 // of entries and fallback namespaces. Only the last one remains in
1360 // the working set to simulate appearing as "in use".
1361 MakeMultipleHitCacheAndGroup(kManifestUrl
, 1);
1362 MakeMultipleHitCacheAndGroup(kManifestUrl2
, 2);
1363 MakeMultipleHitCacheAndGroup(kManifestUrl3
, 3);
1365 // Conduct the test, we should find the response from the last cache
1366 // since it's "in use".
1367 storage()->FindResponseForMainRequest(kEntryUrl
, GURL(), delegate());
1368 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
1371 void MakeMultipleHitCacheAndGroup(const GURL
& manifest_url
, int id
) {
1372 MakeCacheAndGroup(manifest_url
, id
, id
, true);
1373 AppCacheDatabase::EntryRecord entry_record
;
1375 // Add an entry for kEntryUrl
1376 entry_record
.cache_id
= id
;
1377 entry_record
.url
= kEntryUrl
;
1378 entry_record
.flags
= AppCacheEntry::EXPLICIT
;
1379 entry_record
.response_id
= id
;
1380 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1383 AppCacheEntry(entry_record
.flags
, entry_record
.response_id
));
1385 // Add an entry for the manifestUrl
1386 entry_record
.cache_id
= id
;
1387 entry_record
.url
= manifest_url
;
1388 entry_record
.flags
= AppCacheEntry::MANIFEST
;
1389 entry_record
.response_id
= id
+ kManifestEntryIdOffset
;
1390 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1393 AppCacheEntry(entry_record
.flags
, entry_record
.response_id
));
1395 // Add a fallback entry and namespace
1396 entry_record
.cache_id
= id
;
1397 entry_record
.url
= kEntryUrl2
;
1398 entry_record
.flags
= AppCacheEntry::FALLBACK
;
1399 entry_record
.response_id
= id
+ kFallbackEntryIdOffset
;
1400 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1403 AppCacheEntry(entry_record
.flags
, entry_record
.response_id
));
1404 AppCacheDatabase::NamespaceRecord fallback_namespace_record
;
1405 fallback_namespace_record
.cache_id
= id
;
1406 fallback_namespace_record
.namespace_
.target_url
= entry_record
.url
;
1407 fallback_namespace_record
.namespace_
.namespace_url
= kFallbackNamespace
;
1408 fallback_namespace_record
.origin
= manifest_url
.GetOrigin();
1409 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record
));
1410 cache_
->fallback_namespaces_
.push_back(
1411 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1417 void Verify_FindMainResponseWithMultipleHits() {
1418 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
1419 EXPECT_EQ(kManifestUrl3
, delegate()->found_manifest_url_
);
1420 EXPECT_EQ(3, delegate()->found_cache_id_
);
1421 EXPECT_EQ(3, delegate()->found_group_id_
);
1422 EXPECT_EQ(3, delegate()->found_entry_
.response_id());
1423 EXPECT_TRUE(delegate()->found_entry_
.IsExplicit());
1424 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1426 // Conduct another test preferring kManifestUrl
1427 delegate_
.reset(new MockStorageDelegate(this));
1428 PushNextTask(base::Bind(
1429 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2
,
1430 base::Unretained(this)));
1431 storage()->FindResponseForMainRequest(kEntryUrl
, kManifestUrl
, delegate());
1432 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
1435 void Verify_FindMainResponseWithMultipleHits2() {
1436 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
1437 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1438 EXPECT_EQ(1, delegate()->found_cache_id_
);
1439 EXPECT_EQ(1, delegate()->found_group_id_
);
1440 EXPECT_EQ(1, delegate()->found_entry_
.response_id());
1441 EXPECT_TRUE(delegate()->found_entry_
.IsExplicit());
1442 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1444 // Conduct the another test preferring kManifestUrl2
1445 delegate_
.reset(new MockStorageDelegate(this));
1446 PushNextTask(base::Bind(
1447 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3
,
1448 base::Unretained(this)));
1449 storage()->FindResponseForMainRequest(kEntryUrl
, kManifestUrl2
, delegate());
1450 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
1453 void Verify_FindMainResponseWithMultipleHits3() {
1454 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
1455 EXPECT_EQ(kManifestUrl2
, delegate()->found_manifest_url_
);
1456 EXPECT_EQ(2, delegate()->found_cache_id_
);
1457 EXPECT_EQ(2, delegate()->found_group_id_
);
1458 EXPECT_EQ(2, delegate()->found_entry_
.response_id());
1459 EXPECT_TRUE(delegate()->found_entry_
.IsExplicit());
1460 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1462 // Conduct another test with no preferred manifest that hits the fallback.
1463 delegate_
.reset(new MockStorageDelegate(this));
1464 PushNextTask(base::Bind(
1465 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4
,
1466 base::Unretained(this)));
1467 storage()->FindResponseForMainRequest(
1468 kFallbackTestUrl
, GURL(), delegate());
1469 EXPECT_NE(kFallbackTestUrl
, delegate()->found_url_
);
1472 void Verify_FindMainResponseWithMultipleHits4() {
1473 EXPECT_EQ(kFallbackTestUrl
, delegate()->found_url_
);
1474 EXPECT_EQ(kManifestUrl3
, delegate()->found_manifest_url_
);
1475 EXPECT_EQ(3, delegate()->found_cache_id_
);
1476 EXPECT_EQ(3, delegate()->found_group_id_
);
1477 EXPECT_FALSE(delegate()->found_entry_
.has_response_id());
1478 EXPECT_EQ(3 + kFallbackEntryIdOffset
,
1479 delegate()->found_fallback_entry_
.response_id());
1480 EXPECT_TRUE(delegate()->found_fallback_entry_
.IsFallback());
1481 EXPECT_EQ(kEntryUrl2
, delegate()->found_namespace_entry_url_
);
1483 // Conduct another test preferring kManifestUrl2 that hits the fallback.
1484 delegate_
.reset(new MockStorageDelegate(this));
1485 PushNextTask(base::Bind(
1486 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5
,
1487 base::Unretained(this)));
1488 storage()->FindResponseForMainRequest(
1489 kFallbackTestUrl
, kManifestUrl2
, delegate());
1490 EXPECT_NE(kFallbackTestUrl
, delegate()->found_url_
);
1493 void Verify_FindMainResponseWithMultipleHits5() {
1494 EXPECT_EQ(kFallbackTestUrl
, delegate()->found_url_
);
1495 EXPECT_EQ(kManifestUrl2
, delegate()->found_manifest_url_
);
1496 EXPECT_EQ(2, delegate()->found_cache_id_
);
1497 EXPECT_EQ(2, delegate()->found_group_id_
);
1498 EXPECT_FALSE(delegate()->found_entry_
.has_response_id());
1499 EXPECT_EQ(2 + kFallbackEntryIdOffset
,
1500 delegate()->found_fallback_entry_
.response_id());
1501 EXPECT_TRUE(delegate()->found_fallback_entry_
.IsFallback());
1502 EXPECT_EQ(kEntryUrl2
, delegate()->found_namespace_entry_url_
);
1507 // FindMainResponseExclusions -------------------------------
1509 void FindMainResponseExclusionsInDatabase() {
1510 FindMainResponseExclusions(true);
1513 void FindMainResponseExclusionsInWorkingSet() {
1514 FindMainResponseExclusions(false);
1517 void FindMainResponseExclusions(bool drop_from_working_set
) {
1518 // Setup some preconditions. Create a complete cache with a
1519 // foreign entry, an online namespace, and a second online
1520 // namespace nested within a fallback namespace.
1521 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
1522 cache_
->AddEntry(kEntryUrl
,
1523 AppCacheEntry(AppCacheEntry::EXPLICIT
| AppCacheEntry::FOREIGN
, 1));
1524 cache_
->AddEntry(kEntryUrl2
, AppCacheEntry(AppCacheEntry::FALLBACK
, 2));
1525 cache_
->fallback_namespaces_
.push_back(
1526 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1530 cache_
->online_whitelist_namespaces_
.push_back(
1531 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE
, kOnlineNamespace
,
1533 cache_
->online_whitelist_namespaces_
.push_back(
1534 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE
,
1535 kOnlineNamespaceWithinFallback
, GURL(), false));
1537 AppCacheDatabase::EntryRecord entry_record
;
1538 entry_record
.cache_id
= 1;
1539 entry_record
.url
= kEntryUrl
;
1540 entry_record
.flags
= AppCacheEntry::EXPLICIT
| AppCacheEntry::FOREIGN
;
1541 entry_record
.response_id
= 1;
1542 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1543 AppCacheDatabase::OnlineWhiteListRecord whitelist_record
;
1544 whitelist_record
.cache_id
= 1;
1545 whitelist_record
.namespace_url
= kOnlineNamespace
;
1546 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record
));
1547 AppCacheDatabase::NamespaceRecord fallback_namespace_record
;
1548 fallback_namespace_record
.cache_id
= 1;
1549 fallback_namespace_record
.namespace_
.target_url
= kEntryUrl2
;
1550 fallback_namespace_record
.namespace_
.namespace_url
= kFallbackNamespace
;
1551 fallback_namespace_record
.origin
= kManifestUrl
.GetOrigin();
1552 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record
));
1553 whitelist_record
.cache_id
= 1;
1554 whitelist_record
.namespace_url
= kOnlineNamespaceWithinFallback
;
1555 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record
));
1556 if (drop_from_working_set
) {
1561 // We should not find anything for the foreign entry.
1562 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound
,
1563 base::Unretained(this), kEntryUrl
, 1));
1564 storage()->FindResponseForMainRequest(kEntryUrl
, GURL(), delegate());
1567 void Verify_ExclusionNotFound(GURL expected_url
, int phase
) {
1568 EXPECT_EQ(expected_url
, delegate()->found_url_
);
1569 EXPECT_TRUE(delegate()->found_manifest_url_
.is_empty());
1570 EXPECT_EQ(kAppCacheNoCacheId
, delegate()->found_cache_id_
);
1571 EXPECT_EQ(0, delegate()->found_group_id_
);
1572 EXPECT_EQ(kAppCacheNoResponseId
, delegate()->found_entry_
.response_id());
1573 EXPECT_EQ(kAppCacheNoResponseId
,
1574 delegate()->found_fallback_entry_
.response_id());
1575 EXPECT_TRUE(delegate()->found_namespace_entry_url_
.is_empty());
1576 EXPECT_EQ(0, delegate()->found_entry_
.types());
1577 EXPECT_EQ(0, delegate()->found_fallback_entry_
.types());
1580 // We should not find anything for the online namespace.
1582 base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound
,
1583 base::Unretained(this), kOnlineNamespace
, 2));
1584 storage()->FindResponseForMainRequest(
1585 kOnlineNamespace
, GURL(), delegate());
1589 // We should not find anything for the online namespace nested within
1590 // the fallback namespace.
1591 PushNextTask(base::Bind(
1592 &AppCacheStorageImplTest::Verify_ExclusionNotFound
,
1593 base::Unretained(this), kOnlineNamespaceWithinFallback
, 3));
1594 storage()->FindResponseForMainRequest(
1595 kOnlineNamespaceWithinFallback
, GURL(), delegate());
1602 // Reinitialize -------------------------------
1603 // These tests are somewhat of a system integration test.
1604 // They rely on running a mock http server on our IO thread,
1605 // and involves other appcache classes to get some code
1606 // coverage thruout when Reinitialize happens.
1608 class MockServiceObserver
: public AppCacheServiceImpl::Observer
{
1610 explicit MockServiceObserver(AppCacheStorageImplTest
* test
)
1613 void OnServiceReinitialized(
1614 AppCacheStorageReference
* old_storage_ref
) override
{
1615 observed_old_storage_
= old_storage_ref
;
1616 test_
->ScheduleNextTask();
1619 scoped_refptr
<AppCacheStorageReference
> observed_old_storage_
;
1620 AppCacheStorageImplTest
* test_
;
1623 class MockAppCacheFrontend
: public AppCacheFrontend
{
1625 MockAppCacheFrontend() : error_event_was_raised_(false) {}
1627 void OnCacheSelected(int host_id
, const AppCacheInfo
& info
) override
{}
1628 void OnStatusChanged(const std::vector
<int>& host_ids
,
1629 AppCacheStatus status
) override
{}
1630 void OnEventRaised(const std::vector
<int>& host_ids
,
1631 AppCacheEventID event_id
) override
{}
1632 void OnProgressEventRaised(const std::vector
<int>& host_ids
,
1635 int num_complete
) override
{}
1636 void OnErrorEventRaised(const std::vector
<int>& host_ids
,
1637 const AppCacheErrorDetails
& details
) override
{
1638 error_event_was_raised_
= true;
1640 void OnLogMessage(int host_id
,
1641 AppCacheLogLevel log_level
,
1642 const std::string
& message
) override
{}
1643 void OnContentBlocked(int host_id
, const GURL
& manifest_url
) override
{}
1645 bool error_event_was_raised_
;
1648 enum ReinitTestCase
{
1649 CORRUPT_CACHE_ON_INSTALL
,
1650 CORRUPT_CACHE_ON_LOAD_EXISTING
,
1651 CORRUPT_SQL_ON_INSTALL
1654 void Reinitialize1() {
1655 // Recover from a corrupt disk cache discovered while
1656 // installing a new appcache.
1657 Reinitialize(CORRUPT_CACHE_ON_INSTALL
);
1660 void Reinitialize2() {
1661 // Recover from a corrupt disk cache discovered while
1662 // trying to load a resource from an existing appcache.
1663 Reinitialize(CORRUPT_CACHE_ON_LOAD_EXISTING
);
1666 void Reinitialize3() {
1667 // Recover from a corrupt sql database discovered while
1668 // installing a new appcache.
1669 Reinitialize(CORRUPT_SQL_ON_INSTALL
);
1672 void Reinitialize(ReinitTestCase test_case
) {
1673 // Unlike all of the other tests, this one actually read/write files.
1674 ASSERT_TRUE(temp_directory_
.CreateUniqueTempDir());
1676 AppCacheDatabase
db(temp_directory_
.path().AppendASCII("Index"));
1677 EXPECT_TRUE(db
.LazyOpen(true));
1679 if (test_case
== CORRUPT_CACHE_ON_INSTALL
||
1680 test_case
== CORRUPT_CACHE_ON_LOAD_EXISTING
) {
1681 // Create a corrupt/unopenable disk_cache index file.
1682 const std::string
kCorruptData("deadbeef");
1683 base::FilePath disk_cache_directory
=
1684 temp_directory_
.path().AppendASCII("Cache");
1685 ASSERT_TRUE(base::CreateDirectory(disk_cache_directory
));
1686 base::FilePath index_file
= disk_cache_directory
.AppendASCII("index");
1687 EXPECT_EQ(static_cast<int>(kCorruptData
.length()),
1689 index_file
, kCorruptData
.data(), kCorruptData
.length()));
1692 // Create records for a degenerate cached manifest that only contains
1693 // one entry for the manifest file resource.
1694 if (test_case
== CORRUPT_CACHE_ON_LOAD_EXISTING
) {
1695 AppCacheDatabase
db(temp_directory_
.path().AppendASCII("Index"));
1696 GURL manifest_url
= MockHttpServer::GetMockUrl("manifest");
1698 AppCacheDatabase::GroupRecord group_record
;
1699 group_record
.group_id
= 1;
1700 group_record
.manifest_url
= manifest_url
;
1701 group_record
.origin
= manifest_url
.GetOrigin();
1702 EXPECT_TRUE(db
.InsertGroup(&group_record
));
1703 AppCacheDatabase::CacheRecord cache_record
;
1704 cache_record
.cache_id
= 1;
1705 cache_record
.group_id
= 1;
1706 cache_record
.online_wildcard
= false;
1707 cache_record
.update_time
= kZeroTime
;
1708 cache_record
.cache_size
= kDefaultEntrySize
;
1709 EXPECT_TRUE(db
.InsertCache(&cache_record
));
1710 AppCacheDatabase::EntryRecord entry_record
;
1711 entry_record
.cache_id
= 1;
1712 entry_record
.url
= manifest_url
;
1713 entry_record
.flags
= AppCacheEntry::MANIFEST
;
1714 entry_record
.response_id
= 1;
1715 entry_record
.response_size
= kDefaultEntrySize
;
1716 EXPECT_TRUE(db
.InsertEntry(&entry_record
));
1719 // Recreate the service to point at the db and corruption on disk.
1720 service_
.reset(new AppCacheServiceImpl(NULL
));
1721 service_
->set_request_context(io_thread
->request_context());
1722 service_
->Initialize(temp_directory_
.path(),
1723 db_thread
->task_runner(),
1724 db_thread
->task_runner());
1725 mock_quota_manager_proxy_
= new MockQuotaManagerProxy();
1726 service_
->quota_manager_proxy_
= mock_quota_manager_proxy_
;
1727 delegate_
.reset(new MockStorageDelegate(this));
1729 // Additional setup to observe reinitailize happens.
1730 observer_
.reset(new MockServiceObserver(this));
1731 service_
->AddObserver(observer_
.get());
1733 // We continue after the init task is complete including the callback
1734 // on the current thread.
1735 FlushDbThreadTasks();
1736 base::MessageLoop::current()->PostTask(
1738 base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize
,
1739 base::Unretained(this),
1743 void Continue_Reinitialize(ReinitTestCase test_case
) {
1744 const int kMockProcessId
= 1;
1745 backend_
.reset(new AppCacheBackendImpl
);
1746 backend_
->Initialize(service_
.get(), &frontend_
, kMockProcessId
);
1748 if (test_case
== CORRUPT_SQL_ON_INSTALL
) {
1749 // Break the db file
1750 EXPECT_FALSE(database()->was_corruption_detected());
1751 ASSERT_TRUE(sql::test::CorruptSizeInHeader(
1752 temp_directory_
.path().AppendASCII("Index")));
1755 if (test_case
== CORRUPT_CACHE_ON_INSTALL
||
1756 test_case
== CORRUPT_SQL_ON_INSTALL
) {
1757 // Try to create a new appcache, the resulting update job will
1758 // eventually fail when it gets to disk cache initialization.
1759 backend_
->RegisterHost(1);
1760 AppCacheHost
* host1
= backend_
->GetHost(1);
1761 const GURL
kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
1762 host1
->first_party_url_
= kEmptyPageUrl
;
1763 host1
->SelectCache(kEmptyPageUrl
,
1765 MockHttpServer::GetMockUrl("manifest"));
1767 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING
, test_case
);
1768 // Try to access the existing cache manifest.
1769 // The URLRequestJob will eventually fail when it gets to disk
1770 // cache initialization.
1771 backend_
->RegisterHost(2);
1772 AppCacheHost
* host2
= backend_
->GetHost(2);
1773 GURL manifest_url
= MockHttpServer::GetMockUrl("manifest");
1774 request_
= service()->request_context()->CreateRequest(
1775 manifest_url
, net::DEFAULT_PRIORITY
, NULL
, NULL
);
1776 AppCacheInterceptor::SetExtraRequestInfo(
1777 request_
.get(), service_
.get(),
1778 backend_
->process_id(), host2
->host_id(),
1779 RESOURCE_TYPE_MAIN_FRAME
);
1783 PushNextTask(base::Bind(
1784 &AppCacheStorageImplTest::Verify_Reinitialized
,
1785 base::Unretained(this),
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());
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());
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
,
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
) {
1949 &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress
);
1952 TEST_F(AppCacheStorageImplTest
, FindNoMainResponse
) {
1953 RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse
);
1956 TEST_F(AppCacheStorageImplTest
, BasicFindMainResponseInDatabase
) {
1958 &AppCacheStorageImplTest::BasicFindMainResponseInDatabase
);
1961 TEST_F(AppCacheStorageImplTest
, BasicFindMainResponseInWorkingSet
) {
1963 &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet
);
1966 TEST_F(AppCacheStorageImplTest
, BasicFindMainFallbackResponseInDatabase
) {
1968 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase
);
1971 TEST_F(AppCacheStorageImplTest
, BasicFindMainFallbackResponseInWorkingSet
) {
1973 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet
);
1976 TEST_F(AppCacheStorageImplTest
, BasicFindMainInterceptResponseInDatabase
) {
1978 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase
);
1981 TEST_F(AppCacheStorageImplTest
, BasicFindMainInterceptResponseInWorkingSet
) {
1983 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet
);
1986 TEST_F(AppCacheStorageImplTest
, FindMainResponseWithMultipleHits
) {
1988 &AppCacheStorageImplTest::FindMainResponseWithMultipleHits
);
1991 TEST_F(AppCacheStorageImplTest
, FindMainResponseExclusionsInDatabase
) {
1993 &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase
);
1996 TEST_F(AppCacheStorageImplTest
, FindMainResponseExclusionsInWorkingSet
) {
1998 &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet
);
2001 TEST_F(AppCacheStorageImplTest
, FindInterceptPatternMatchInWorkingSet
) {
2003 &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet
);
2006 TEST_F(AppCacheStorageImplTest
, FindInterceptPatternMatchInDatabase
) {
2008 &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase
);
2011 TEST_F(AppCacheStorageImplTest
, FindFallbackPatternMatchInWorkingSet
) {
2013 &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet
);
2016 TEST_F(AppCacheStorageImplTest
, FindFallbackPatternMatchInDatabase
) {
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