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/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 "testing/gtest/include/gtest/gtest.h"
35 #include "webkit/browser/quota/quota_manager.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 virtual net::URLRequestJob
* MaybeCreateJob(
130 net::URLRequest
* request
,
131 net::NetworkDelegate
* network_delegate
) const OVERRIDE
{
132 return MockHttpServer::CreateJob(request
, network_delegate
);
136 class IOThread
: public base::Thread
{
138 explicit IOThread(const char* name
)
139 : base::Thread(name
) {
142 virtual ~IOThread() {
146 net::URLRequestContext
* request_context() {
147 return request_context_
.get();
150 virtual void Init() OVERRIDE
{
151 scoped_ptr
<net::URLRequestJobFactoryImpl
> factory(
152 new net::URLRequestJobFactoryImpl());
153 factory
->SetProtocolHandler("http", new MockHttpServerJobFactory
);
154 job_factory_
= factory
.Pass();
155 request_context_
.reset(new net::TestURLRequestContext());
156 request_context_
->set_job_factory(job_factory_
.get());
157 AppCacheInterceptor::EnsureRegistered();
160 virtual void CleanUp() OVERRIDE
{
161 request_context_
.reset();
162 job_factory_
.reset();
166 scoped_ptr
<net::URLRequestJobFactory
> job_factory_
;
167 scoped_ptr
<net::URLRequestContext
> request_context_
;
170 scoped_ptr
<IOThread
> io_thread
;
171 scoped_ptr
<base::Thread
> db_thread
;
175 class AppCacheStorageImplTest
: public testing::Test
{
177 class MockStorageDelegate
: public AppCacheStorage::Delegate
{
179 explicit MockStorageDelegate(AppCacheStorageImplTest
* test
)
180 : loaded_cache_id_(0), stored_group_success_(false),
181 would_exceed_quota_(false), obsoleted_success_(false),
182 found_cache_id_(kAppCacheNoCacheId
), test_(test
) {
185 virtual void OnCacheLoaded(AppCache
* cache
, int64 cache_id
) OVERRIDE
{
186 loaded_cache_
= cache
;
187 loaded_cache_id_
= cache_id
;
188 test_
->ScheduleNextTask();
191 virtual void OnGroupLoaded(AppCacheGroup
* group
,
192 const GURL
& manifest_url
) OVERRIDE
{
193 loaded_group_
= group
;
194 loaded_manifest_url_
= manifest_url
;
195 loaded_groups_newest_cache_
= group
? group
->newest_complete_cache()
197 test_
->ScheduleNextTask();
200 virtual void OnGroupAndNewestCacheStored(
201 AppCacheGroup
* group
, AppCache
* newest_cache
, bool success
,
202 bool would_exceed_quota
) OVERRIDE
{
203 stored_group_
= group
;
204 stored_group_success_
= success
;
205 would_exceed_quota_
= would_exceed_quota
;
206 test_
->ScheduleNextTask();
209 virtual void OnGroupMadeObsolete(AppCacheGroup
* group
,
211 int response_code
) OVERRIDE
{
212 obsoleted_group_
= group
;
213 obsoleted_success_
= success
;
214 test_
->ScheduleNextTask();
217 virtual void OnMainResponseFound(const GURL
& url
,
218 const AppCacheEntry
& entry
,
219 const GURL
& namespace_entry_url
,
220 const AppCacheEntry
& fallback_entry
,
223 const GURL
& manifest_url
) OVERRIDE
{
225 found_entry_
= entry
;
226 found_namespace_entry_url_
= namespace_entry_url
;
227 found_fallback_entry_
= fallback_entry
;
228 found_cache_id_
= cache_id
;
229 found_group_id_
= group_id
;
230 found_manifest_url_
= manifest_url
;
231 test_
->ScheduleNextTask();
234 scoped_refptr
<AppCache
> loaded_cache_
;
235 int64 loaded_cache_id_
;
236 scoped_refptr
<AppCacheGroup
> loaded_group_
;
237 GURL loaded_manifest_url_
;
238 scoped_refptr
<AppCache
> loaded_groups_newest_cache_
;
239 scoped_refptr
<AppCacheGroup
> stored_group_
;
240 bool stored_group_success_
;
241 bool would_exceed_quota_
;
242 scoped_refptr
<AppCacheGroup
> obsoleted_group_
;
243 bool obsoleted_success_
;
245 AppCacheEntry found_entry_
;
246 GURL found_namespace_entry_url_
;
247 AppCacheEntry found_fallback_entry_
;
248 int64 found_cache_id_
;
249 int64 found_group_id_
;
250 GURL found_manifest_url_
;
251 AppCacheStorageImplTest
* test_
;
254 class MockQuotaManager
: public quota::QuotaManager
{
257 : QuotaManager(true /* is_incognito */,
259 io_thread
->message_loop_proxy().get(),
260 db_thread
->message_loop_proxy().get(),
264 virtual void GetUsageAndQuota(
266 quota::StorageType type
,
267 const GetUsageAndQuotaCallback
& callback
) OVERRIDE
{
268 EXPECT_EQ(quota::kStorageTypeTemporary
, type
);
270 base::MessageLoop::current()->PostTask(
272 base::Bind(&MockQuotaManager::CallCallback
,
273 base::Unretained(this),
277 CallCallback(callback
);
280 void CallCallback(const GetUsageAndQuotaCallback
& callback
) {
281 callback
.Run(quota::kQuotaStatusOk
, 0, kMockQuota
);
287 virtual ~MockQuotaManager() {}
290 class MockQuotaManagerProxy
: public quota::QuotaManagerProxy
{
292 MockQuotaManagerProxy()
293 : QuotaManagerProxy(NULL
, NULL
),
294 notify_storage_accessed_count_(0),
295 notify_storage_modified_count_(0),
297 mock_manager_(new MockQuotaManager
) {
298 manager_
= mock_manager_
.get();
301 virtual void NotifyStorageAccessed(quota::QuotaClient::ID client_id
,
303 quota::StorageType type
) OVERRIDE
{
304 EXPECT_EQ(quota::QuotaClient::kAppcache
, client_id
);
305 EXPECT_EQ(quota::kStorageTypeTemporary
, type
);
306 ++notify_storage_accessed_count_
;
307 last_origin_
= origin
;
310 virtual void NotifyStorageModified(quota::QuotaClient::ID client_id
,
312 quota::StorageType type
,
313 int64 delta
) OVERRIDE
{
314 EXPECT_EQ(quota::QuotaClient::kAppcache
, client_id
);
315 EXPECT_EQ(quota::kStorageTypeTemporary
, type
);
316 ++notify_storage_modified_count_
;
317 last_origin_
= origin
;
321 // Not needed for our tests.
322 virtual void RegisterClient(quota::QuotaClient
* client
) OVERRIDE
{}
323 virtual void NotifyOriginInUse(const GURL
& origin
) OVERRIDE
{}
324 virtual void NotifyOriginNoLongerInUse(const GURL
& origin
) OVERRIDE
{}
325 virtual void SetUsageCacheEnabled(quota::QuotaClient::ID client_id
,
327 quota::StorageType type
,
328 bool enabled
) OVERRIDE
{}
329 virtual void GetUsageAndQuota(
330 base::SequencedTaskRunner
* original_task_runner
,
332 quota::StorageType type
,
333 const GetUsageAndQuotaCallback
& callback
) OVERRIDE
{}
335 int notify_storage_accessed_count_
;
336 int notify_storage_modified_count_
;
339 scoped_refptr
<MockQuotaManager
> mock_manager_
;
342 virtual ~MockQuotaManagerProxy() {}
345 template <class Method
>
346 void RunMethod(Method method
) {
350 // Helper callback to run a test on our io_thread. The io_thread is spun up
351 // once and reused for all tests.
352 template <class Method
>
353 void MethodWrapper(Method method
) {
356 // Ensure InitTask execution prior to conducting a test.
357 FlushDbThreadTasks();
359 // We also have to wait for InitTask completion call to be performed
360 // on the IO thread prior to running the test. Its guaranteed to be
361 // queued by this time.
362 base::MessageLoop::current()->PostTask(
364 base::Bind(&AppCacheStorageImplTest::RunMethod
<Method
>,
365 base::Unretained(this),
369 static void SetUpTestCase() {
370 // We start both threads as TYPE_IO because we also use the db_thead
371 // for the disk_cache which needs to be of TYPE_IO.
372 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
373 io_thread
.reset(new IOThread("AppCacheTest.IOThread"));
374 ASSERT_TRUE(io_thread
->StartWithOptions(options
));
375 db_thread
.reset(new base::Thread("AppCacheTest::DBThread"));
376 ASSERT_TRUE(db_thread
->StartWithOptions(options
));
379 static void TearDownTestCase() {
380 io_thread
.reset(NULL
);
381 db_thread
.reset(NULL
);
384 // Test harness --------------------------------------------------
386 AppCacheStorageImplTest() {
389 template <class Method
>
390 void RunTestOnIOThread(Method method
) {
391 test_finished_event_
.reset(new base::WaitableEvent(false, false));
392 io_thread
->message_loop()->PostTask(
393 FROM_HERE
, base::Bind(&AppCacheStorageImplTest::MethodWrapper
<Method
>,
394 base::Unretained(this), method
));
395 test_finished_event_
->Wait();
399 DCHECK(base::MessageLoop::current() == io_thread
->message_loop());
400 service_
.reset(new AppCacheServiceImpl(NULL
));
401 service_
->Initialize(
402 base::FilePath(), db_thread
->message_loop_proxy().get(), NULL
);
403 mock_quota_manager_proxy_
= new MockQuotaManagerProxy();
404 service_
->quota_manager_proxy_
= mock_quota_manager_proxy_
;
405 delegate_
.reset(new MockStorageDelegate(this));
408 void TearDownTest() {
409 DCHECK(base::MessageLoop::current() == io_thread
->message_loop());
410 storage()->CancelDelegateCallbacks(delegate());
414 mock_quota_manager_proxy_
= NULL
;
417 FlushDbThreadTasks();
420 void TestFinished() {
421 // We unwind the stack prior to finishing up to let stack
422 // based objects get deleted.
423 DCHECK(base::MessageLoop::current() == io_thread
->message_loop());
424 base::MessageLoop::current()->PostTask(
426 base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound
,
427 base::Unretained(this)));
430 void TestFinishedUnwound() {
432 test_finished_event_
->Signal();
435 void PushNextTask(const base::Closure
& task
) {
436 task_stack_
.push(task
);
439 void ScheduleNextTask() {
440 DCHECK(base::MessageLoop::current() == io_thread
->message_loop());
441 if (task_stack_
.empty()) {
444 base::MessageLoop::current()->PostTask(FROM_HERE
, task_stack_
.top());
448 static void SignalEvent(base::WaitableEvent
* event
) {
452 void FlushDbThreadTasks() {
453 // We pump a task thru the db thread to ensure any tasks previously
454 // scheduled on that thread have been performed prior to return.
455 base::WaitableEvent
event(false, false);
456 db_thread
->message_loop()->PostTask(
457 FROM_HERE
, base::Bind(&AppCacheStorageImplTest::SignalEvent
, &event
));
461 // LoadCache_Miss ----------------------------------------------------
463 void LoadCache_Miss() {
464 // Attempt to load a cache that doesn't exist. Should
465 // complete asynchronously.
466 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Miss
,
467 base::Unretained(this)));
469 storage()->LoadCache(111, delegate());
470 EXPECT_NE(111, delegate()->loaded_cache_id_
);
473 void Verify_LoadCache_Miss() {
474 EXPECT_EQ(111, delegate()->loaded_cache_id_
);
475 EXPECT_FALSE(delegate()->loaded_cache_
.get());
476 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
477 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
481 // LoadCache_NearHit -------------------------------------------------
483 void LoadCache_NearHit() {
484 // Attempt to load a cache that is currently in use
485 // and does not require loading from storage. This
486 // load should complete syncly.
488 // Setup some preconditions. Make an 'unstored' cache for
489 // us to load. The ctor should put it in the working set.
490 int64 cache_id
= storage()->NewCacheId();
491 scoped_refptr
<AppCache
> cache(new AppCache(storage(), cache_id
));
494 storage()->LoadCache(cache_id
, delegate());
495 EXPECT_EQ(cache_id
, delegate()->loaded_cache_id_
);
496 EXPECT_EQ(cache
.get(), delegate()->loaded_cache_
.get());
497 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
498 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
502 // CreateGroup --------------------------------------------
504 void CreateGroupInEmptyOrigin() {
505 // Attempt to load a group that doesn't exist, one should
506 // be created for us, but not stored.
508 // Since the origin has no groups, the storage class will respond
510 storage()->LoadOrCreateGroup(kManifestUrl
, delegate());
511 Verify_CreateGroup();
514 void CreateGroupInPopulatedOrigin() {
515 // Attempt to load a group that doesn't exist, one should
516 // be created for us, but not stored.
517 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_CreateGroup
,
518 base::Unretained(this)));
520 // Since the origin has groups, storage class will have to
521 // consult the database and completion will be async.
522 storage()->usage_map_
[kOrigin
] = kDefaultEntrySize
;
524 storage()->LoadOrCreateGroup(kManifestUrl
, delegate());
525 EXPECT_FALSE(delegate()->loaded_group_
.get());
528 void Verify_CreateGroup() {
529 EXPECT_EQ(kManifestUrl
, delegate()->loaded_manifest_url_
);
530 EXPECT_TRUE(delegate()->loaded_group_
.get());
531 EXPECT_TRUE(delegate()->loaded_group_
->HasOneRef());
532 EXPECT_FALSE(delegate()->loaded_group_
->newest_complete_cache());
534 // Should not have been stored in the database.
535 AppCacheDatabase::GroupRecord record
;
536 EXPECT_FALSE(database()->FindGroup(
537 delegate()->loaded_group_
->group_id(), &record
));
539 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
540 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
545 // LoadGroupAndCache_FarHit --------------------------------------
547 void LoadGroupAndCache_FarHit() {
548 // Attempt to load a cache that is not currently in use
549 // and does require loading from disk. This
550 // load should complete asynchronously.
551 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadCache_Far_Hit
,
552 base::Unretained(this)));
554 // Setup some preconditions. Create a group and newest cache that
555 // appear to be "stored" and "not currently in use".
556 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
560 // Conduct the cache load test, completes async
561 storage()->LoadCache(1, delegate());
564 void Verify_LoadCache_Far_Hit() {
565 EXPECT_TRUE(delegate()->loaded_cache_
.get());
566 EXPECT_TRUE(delegate()->loaded_cache_
->HasOneRef());
567 EXPECT_EQ(1, delegate()->loaded_cache_id_
);
569 // The group should also have been loaded.
570 EXPECT_TRUE(delegate()->loaded_cache_
->owning_group());
571 EXPECT_TRUE(delegate()->loaded_cache_
->owning_group()->HasOneRef());
572 EXPECT_EQ(1, delegate()->loaded_cache_
->owning_group()->group_id());
574 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
575 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
577 // Drop things from the working set.
578 delegate()->loaded_cache_
= NULL
;
579 EXPECT_FALSE(delegate()->loaded_group_
.get());
581 // Conduct the group load test, also complete asynchronously.
582 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_LoadGroup_Far_Hit
,
583 base::Unretained(this)));
585 storage()->LoadOrCreateGroup(kManifestUrl
, delegate());
588 void Verify_LoadGroup_Far_Hit() {
589 EXPECT_TRUE(delegate()->loaded_group_
.get());
590 EXPECT_EQ(kManifestUrl
, delegate()->loaded_manifest_url_
);
591 EXPECT_TRUE(delegate()->loaded_group_
->newest_complete_cache());
592 delegate()->loaded_groups_newest_cache_
= NULL
;
593 EXPECT_TRUE(delegate()->loaded_group_
->HasOneRef());
594 EXPECT_EQ(2, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
595 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
599 // StoreNewGroup --------------------------------------
601 void StoreNewGroup() {
602 // Store a group and its newest cache. Should complete asynchronously.
603 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreNewGroup
,
604 base::Unretained(this)));
606 // Setup some preconditions. Create a group and newest cache that
607 // appear to be "unstored".
608 group_
= new AppCacheGroup(
609 storage(), kManifestUrl
, storage()->NewGroupId());
610 cache_
= new AppCache(storage(), storage()->NewCacheId());
611 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::EXPLICIT
, 1,
613 // Hold a ref to the cache simulate the UpdateJob holding that ref,
614 // and hold a ref to the group to simulate the CacheHost holding that ref.
616 // Have the quota manager retrun asynchronously for this test.
617 mock_quota_manager_proxy_
->mock_manager_
->async_
= true;
619 // Conduct the store test.
620 storage()->StoreGroupAndNewestCache(group_
.get(), cache_
.get(), delegate());
621 EXPECT_FALSE(delegate()->stored_group_success_
);
624 void Verify_StoreNewGroup() {
625 EXPECT_TRUE(delegate()->stored_group_success_
);
626 EXPECT_EQ(group_
.get(), delegate()->stored_group_
.get());
627 EXPECT_EQ(cache_
.get(), group_
->newest_complete_cache());
628 EXPECT_TRUE(cache_
->is_complete());
630 // Should have been stored in the database.
631 AppCacheDatabase::GroupRecord group_record
;
632 AppCacheDatabase::CacheRecord cache_record
;
633 EXPECT_TRUE(database()->FindGroup(group_
->group_id(), &group_record
));
634 EXPECT_TRUE(database()->FindCache(cache_
->cache_id(), &cache_record
));
636 // Verify quota bookkeeping
637 EXPECT_EQ(kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
638 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
639 EXPECT_EQ(kOrigin
, mock_quota_manager_proxy_
->last_origin_
);
640 EXPECT_EQ(kDefaultEntrySize
, mock_quota_manager_proxy_
->last_delta_
);
645 // StoreExistingGroup --------------------------------------
647 void StoreExistingGroup() {
648 // Store a group and its newest cache. Should complete asynchronously.
649 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_StoreExistingGroup
,
650 base::Unretained(this)));
652 // Setup some preconditions. Create a group and old complete cache
653 // that appear to be "stored"
654 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
655 EXPECT_EQ(kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
657 // And a newest unstored complete cache.
658 cache2_
= new AppCache(storage(), 2);
659 cache2_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::MASTER
, 1,
660 kDefaultEntrySize
+ 100));
663 storage()->StoreGroupAndNewestCache(
664 group_
.get(), cache2_
.get(), delegate());
665 EXPECT_FALSE(delegate()->stored_group_success_
);
668 void Verify_StoreExistingGroup() {
669 EXPECT_TRUE(delegate()->stored_group_success_
);
670 EXPECT_EQ(group_
.get(), delegate()->stored_group_
.get());
671 EXPECT_EQ(cache2_
.get(), group_
->newest_complete_cache());
672 EXPECT_TRUE(cache2_
->is_complete());
674 // The new cache should have been stored in the database.
675 AppCacheDatabase::GroupRecord group_record
;
676 AppCacheDatabase::CacheRecord cache_record
;
677 EXPECT_TRUE(database()->FindGroup(1, &group_record
));
678 EXPECT_TRUE(database()->FindCache(2, &cache_record
));
680 // The old cache should have been deleted
681 EXPECT_FALSE(database()->FindCache(1, &cache_record
));
683 // Verify quota bookkeeping
684 EXPECT_EQ(kDefaultEntrySize
+ 100, storage()->usage_map_
[kOrigin
]);
685 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
686 EXPECT_EQ(kOrigin
, mock_quota_manager_proxy_
->last_origin_
);
687 EXPECT_EQ(100, mock_quota_manager_proxy_
->last_delta_
);
692 // StoreExistingGroupExistingCache -------------------------------
694 void StoreExistingGroupExistingCache() {
695 // Store a group with updates to its existing newest complete cache.
696 // Setup some preconditions. Create a group and a complete cache that
697 // appear to be "stored".
699 // Setup some preconditions. Create a group and old complete cache
700 // that appear to be "stored"
701 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
702 EXPECT_EQ(kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
705 base::Time now
= base::Time::Now();
706 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::MASTER
, 1, 100));
707 cache_
->set_update_time(now
);
709 PushNextTask(base::Bind(
710 &AppCacheStorageImplTest::Verify_StoreExistingGroupExistingCache
,
711 base::Unretained(this), now
));
714 EXPECT_EQ(cache_
, group_
->newest_complete_cache());
715 storage()->StoreGroupAndNewestCache(group_
.get(), cache_
.get(), delegate());
716 EXPECT_FALSE(delegate()->stored_group_success_
);
719 void Verify_StoreExistingGroupExistingCache(
720 base::Time expected_update_time
) {
721 EXPECT_TRUE(delegate()->stored_group_success_
);
722 EXPECT_EQ(cache_
, group_
->newest_complete_cache());
724 AppCacheDatabase::CacheRecord cache_record
;
725 EXPECT_TRUE(database()->FindCache(1, &cache_record
));
726 EXPECT_EQ(1, cache_record
.cache_id
);
727 EXPECT_EQ(1, cache_record
.group_id
);
728 EXPECT_FALSE(cache_record
.online_wildcard
);
729 EXPECT_TRUE(expected_update_time
== cache_record
.update_time
);
730 EXPECT_EQ(100 + kDefaultEntrySize
, cache_record
.cache_size
);
732 std::vector
<AppCacheDatabase::EntryRecord
> entry_records
;
733 EXPECT_TRUE(database()->FindEntriesForCache(1, &entry_records
));
734 EXPECT_EQ(2U, entry_records
.size());
735 if (entry_records
[0].url
== kDefaultEntryUrl
)
736 entry_records
.erase(entry_records
.begin());
737 EXPECT_EQ(1 , entry_records
[0].cache_id
);
738 EXPECT_EQ(kEntryUrl
, entry_records
[0].url
);
739 EXPECT_EQ(AppCacheEntry::MASTER
, entry_records
[0].flags
);
740 EXPECT_EQ(1, entry_records
[0].response_id
);
741 EXPECT_EQ(100, entry_records
[0].response_size
);
743 // Verify quota bookkeeping
744 EXPECT_EQ(100 + kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
745 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
746 EXPECT_EQ(kOrigin
, mock_quota_manager_proxy_
->last_origin_
);
747 EXPECT_EQ(100, mock_quota_manager_proxy_
->last_delta_
);
752 // FailStoreGroup --------------------------------------
754 void FailStoreGroup() {
755 // Store a group and its newest cache. Should complete asynchronously.
756 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FailStoreGroup
,
757 base::Unretained(this)));
759 // Setup some preconditions. Create a group and newest cache that
760 // appear to be "unstored" and big enough to exceed the 5M limit.
761 const int64 kTooBig
= 10 * 1024 * 1024; // 10M
762 group_
= new AppCacheGroup(
763 storage(), kManifestUrl
, storage()->NewGroupId());
764 cache_
= new AppCache(storage(), storage()->NewCacheId());
765 cache_
->AddEntry(kManifestUrl
,
766 AppCacheEntry(AppCacheEntry::MANIFEST
, 1, kTooBig
));
767 // Hold a ref to the cache simulate the UpdateJob holding that ref,
768 // and hold a ref to the group to simulate the CacheHost holding that ref.
770 // Conduct the store test.
771 storage()->StoreGroupAndNewestCache(group_
.get(), cache_
.get(), delegate());
772 EXPECT_FALSE(delegate()->stored_group_success_
); // Expected to be async.
775 void Verify_FailStoreGroup() {
776 EXPECT_FALSE(delegate()->stored_group_success_
);
777 EXPECT_TRUE(delegate()->would_exceed_quota_
);
779 // Should not have been stored in the database.
780 AppCacheDatabase::GroupRecord group_record
;
781 AppCacheDatabase::CacheRecord cache_record
;
782 EXPECT_FALSE(database()->FindGroup(group_
->group_id(), &group_record
));
783 EXPECT_FALSE(database()->FindCache(cache_
->cache_id(), &cache_record
));
785 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_accessed_count_
);
786 EXPECT_EQ(0, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
791 // MakeGroupObsolete -------------------------------
793 void MakeGroupObsolete() {
794 // Make a group obsolete, should complete asynchronously.
795 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_MakeGroupObsolete
,
796 base::Unretained(this)));
798 // Setup some preconditions. Create a group and newest cache that
799 // appears to be "stored" and "currently in use".
800 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
801 EXPECT_EQ(kDefaultEntrySize
, storage()->usage_map_
[kOrigin
]);
803 // Also insert some related records.
804 AppCacheDatabase::EntryRecord entry_record
;
805 entry_record
.cache_id
= 1;
806 entry_record
.flags
= AppCacheEntry::FALLBACK
;
807 entry_record
.response_id
= 1;
808 entry_record
.url
= kEntryUrl
;
809 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
811 AppCacheDatabase::NamespaceRecord fallback_namespace_record
;
812 fallback_namespace_record
.cache_id
= 1;
813 fallback_namespace_record
.namespace_
.target_url
= kEntryUrl
;
814 fallback_namespace_record
.namespace_
.namespace_url
= kFallbackNamespace
;
815 fallback_namespace_record
.origin
= kManifestUrl
.GetOrigin();
816 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record
));
818 AppCacheDatabase::OnlineWhiteListRecord online_whitelist_record
;
819 online_whitelist_record
.cache_id
= 1;
820 online_whitelist_record
.namespace_url
= kOnlineNamespace
;
821 EXPECT_TRUE(database()->InsertOnlineWhiteList(&online_whitelist_record
));
824 storage()->MakeGroupObsolete(group_
.get(), delegate(), 0);
825 EXPECT_FALSE(group_
->is_obsolete());
828 void Verify_MakeGroupObsolete() {
829 EXPECT_TRUE(delegate()->obsoleted_success_
);
830 EXPECT_EQ(group_
.get(), delegate()->obsoleted_group_
.get());
831 EXPECT_TRUE(group_
->is_obsolete());
832 EXPECT_TRUE(storage()->usage_map_
.empty());
834 // The cache and group have been deleted from the database.
835 AppCacheDatabase::GroupRecord group_record
;
836 AppCacheDatabase::CacheRecord cache_record
;
837 EXPECT_FALSE(database()->FindGroup(1, &group_record
));
838 EXPECT_FALSE(database()->FindCache(1, &cache_record
));
840 // The related records should have been deleted too.
841 std::vector
<AppCacheDatabase::EntryRecord
> entry_records
;
842 database()->FindEntriesForCache(1, &entry_records
);
843 EXPECT_TRUE(entry_records
.empty());
844 std::vector
<AppCacheDatabase::NamespaceRecord
> intercept_records
;
845 std::vector
<AppCacheDatabase::NamespaceRecord
> fallback_records
;
846 database()->FindNamespacesForCache(
847 1, &intercept_records
, &fallback_records
);
848 EXPECT_TRUE(fallback_records
.empty());
849 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelist_records
;
850 database()->FindOnlineWhiteListForCache(1, &whitelist_records
);
851 EXPECT_TRUE(whitelist_records
.empty());
853 // Verify quota bookkeeping
854 EXPECT_TRUE(storage()->usage_map_
.empty());
855 EXPECT_EQ(1, mock_quota_manager_proxy_
->notify_storage_modified_count_
);
856 EXPECT_EQ(kOrigin
, mock_quota_manager_proxy_
->last_origin_
);
857 EXPECT_EQ(-kDefaultEntrySize
, mock_quota_manager_proxy_
->last_delta_
);
862 // MarkEntryAsForeign -------------------------------
864 void MarkEntryAsForeign() {
865 // Setup some preconditions. Create a cache with an entry
866 // in storage and in the working set.
867 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
868 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::EXPLICIT
));
869 AppCacheDatabase::EntryRecord entry_record
;
870 entry_record
.cache_id
= 1;
871 entry_record
.url
= kEntryUrl
;
872 entry_record
.flags
= AppCacheEntry::EXPLICIT
;
873 entry_record
.response_id
= 0;
874 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
875 EXPECT_FALSE(cache_
->GetEntry(kEntryUrl
)->IsForeign());
878 storage()->MarkEntryAsForeign(kEntryUrl
, 1);
880 // The entry in the working set should have been updated syncly.
881 EXPECT_TRUE(cache_
->GetEntry(kEntryUrl
)->IsForeign());
882 EXPECT_TRUE(cache_
->GetEntry(kEntryUrl
)->IsExplicit());
884 // And the entry in storage should also be updated, but that
885 // happens asynchronously on the db thread.
886 FlushDbThreadTasks();
887 AppCacheDatabase::EntryRecord entry_record2
;
888 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl
, &entry_record2
));
889 EXPECT_EQ(AppCacheEntry::EXPLICIT
| AppCacheEntry::FOREIGN
,
890 entry_record2
.flags
);
894 // MarkEntryAsForeignWithLoadInProgress -------------------------------
896 void MarkEntryAsForeignWithLoadInProgress() {
897 PushNextTask(base::Bind(
898 &AppCacheStorageImplTest::Verify_MarkEntryAsForeignWithLoadInProgress
,
899 base::Unretained(this)));
901 // Setup some preconditions. Create a cache with an entry
902 // in storage, but not in the working set.
903 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
904 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::EXPLICIT
));
905 AppCacheDatabase::EntryRecord entry_record
;
906 entry_record
.cache_id
= 1;
907 entry_record
.url
= kEntryUrl
;
908 entry_record
.flags
= AppCacheEntry::EXPLICIT
;
909 entry_record
.response_id
= 0;
910 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
911 EXPECT_FALSE(cache_
->GetEntry(kEntryUrl
)->IsForeign());
912 EXPECT_TRUE(cache_
->HasOneRef());
916 // Conduct the test, start a cache load, and prior to completion
917 // of that load, mark the entry as foreign.
918 storage()->LoadCache(1, delegate());
919 storage()->MarkEntryAsForeign(kEntryUrl
, 1);
922 void Verify_MarkEntryAsForeignWithLoadInProgress() {
923 EXPECT_EQ(1, delegate()->loaded_cache_id_
);
924 EXPECT_TRUE(delegate()->loaded_cache_
.get());
926 // The entry in the working set should have been updated upon load.
927 EXPECT_TRUE(delegate()->loaded_cache_
->GetEntry(kEntryUrl
)->IsForeign());
928 EXPECT_TRUE(delegate()->loaded_cache_
->GetEntry(kEntryUrl
)->IsExplicit());
930 // And the entry in storage should also be updated.
931 FlushDbThreadTasks();
932 AppCacheDatabase::EntryRecord entry_record
;
933 EXPECT_TRUE(database()->FindEntry(1, kEntryUrl
, &entry_record
));
934 EXPECT_EQ(AppCacheEntry::EXPLICIT
| AppCacheEntry::FOREIGN
,
939 // FindNoMainResponse -------------------------------
941 void FindNoMainResponse() {
942 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_FindNoMainResponse
,
943 base::Unretained(this)));
946 storage()->FindResponseForMainRequest(kEntryUrl
, GURL(), delegate());
947 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
950 void Verify_FindNoMainResponse() {
951 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
952 EXPECT_TRUE(delegate()->found_manifest_url_
.is_empty());
953 EXPECT_EQ(kAppCacheNoCacheId
, delegate()->found_cache_id_
);
954 EXPECT_EQ(kAppCacheNoResponseId
, delegate()->found_entry_
.response_id());
955 EXPECT_EQ(kAppCacheNoResponseId
,
956 delegate()->found_fallback_entry_
.response_id());
957 EXPECT_TRUE(delegate()->found_namespace_entry_url_
.is_empty());
958 EXPECT_EQ(0, delegate()->found_entry_
.types());
959 EXPECT_EQ(0, delegate()->found_fallback_entry_
.types());
963 // BasicFindMainResponse -------------------------------
965 void BasicFindMainResponseInDatabase() {
966 BasicFindMainResponse(true);
969 void BasicFindMainResponseInWorkingSet() {
970 BasicFindMainResponse(false);
973 void BasicFindMainResponse(bool drop_from_working_set
) {
974 PushNextTask(base::Bind(
975 &AppCacheStorageImplTest::Verify_BasicFindMainResponse
,
976 base::Unretained(this)));
978 // Setup some preconditions. Create a complete cache with an entry
980 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
981 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::EXPLICIT
, 1));
982 AppCacheDatabase::EntryRecord entry_record
;
983 entry_record
.cache_id
= 1;
984 entry_record
.url
= kEntryUrl
;
985 entry_record
.flags
= AppCacheEntry::EXPLICIT
;
986 entry_record
.response_id
= 1;
987 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
989 // Optionally drop the cache/group pair from the working set.
990 if (drop_from_working_set
) {
991 EXPECT_TRUE(cache_
->HasOneRef());
993 EXPECT_TRUE(group_
->HasOneRef());
998 storage()->FindResponseForMainRequest(kEntryUrl
, GURL(), delegate());
999 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
1002 void Verify_BasicFindMainResponse() {
1003 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
1004 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1005 EXPECT_EQ(1, delegate()->found_cache_id_
);
1006 EXPECT_EQ(2, delegate()->found_group_id_
);
1007 EXPECT_EQ(1, delegate()->found_entry_
.response_id());
1008 EXPECT_TRUE(delegate()->found_entry_
.IsExplicit());
1009 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1013 // BasicFindMainFallbackResponse -------------------------------
1015 void BasicFindMainFallbackResponseInDatabase() {
1016 BasicFindMainFallbackResponse(true);
1019 void BasicFindMainFallbackResponseInWorkingSet() {
1020 BasicFindMainFallbackResponse(false);
1023 void BasicFindMainFallbackResponse(bool drop_from_working_set
) {
1024 PushNextTask(base::Bind(
1025 &AppCacheStorageImplTest::Verify_BasicFindMainFallbackResponse
,
1026 base::Unretained(this)));
1028 // Setup some preconditions. Create a complete cache with a
1029 // fallback namespace and entry.
1030 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
1031 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::FALLBACK
, 1));
1032 cache_
->AddEntry(kEntryUrl2
, AppCacheEntry(AppCacheEntry::FALLBACK
, 2));
1033 cache_
->fallback_namespaces_
.push_back(
1034 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1035 kFallbackNamespace2
,
1038 cache_
->fallback_namespaces_
.push_back(
1039 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1043 AppCacheDatabase::CacheRecord cache_record
;
1044 std::vector
<AppCacheDatabase::EntryRecord
> entries
;
1045 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1046 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1047 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1048 cache_
->ToDatabaseRecords(group_
.get(),
1055 std::vector
<AppCacheDatabase::EntryRecord
>::const_iterator iter
=
1057 while (iter
!= entries
.end()) {
1058 // MakeCacheAndGroup has inserted the default entry record already.
1059 if (iter
->url
!= kDefaultEntryUrl
)
1060 EXPECT_TRUE(database()->InsertEntry(&(*iter
)));
1064 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks
));
1065 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists
));
1066 if (drop_from_working_set
) {
1067 EXPECT_TRUE(cache_
->HasOneRef());
1069 EXPECT_TRUE(group_
->HasOneRef());
1073 // Conduct the test. The test url is in both fallback namespace urls,
1074 // but should match the longer of the two.
1075 storage()->FindResponseForMainRequest(kFallbackTestUrl
, GURL(), delegate());
1076 EXPECT_NE(kFallbackTestUrl
, delegate()->found_url_
);
1079 void Verify_BasicFindMainFallbackResponse() {
1080 EXPECT_EQ(kFallbackTestUrl
, delegate()->found_url_
);
1081 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1082 EXPECT_EQ(1, delegate()->found_cache_id_
);
1083 EXPECT_EQ(2, delegate()->found_group_id_
);
1084 EXPECT_FALSE(delegate()->found_entry_
.has_response_id());
1085 EXPECT_EQ(2, delegate()->found_fallback_entry_
.response_id());
1086 EXPECT_EQ(kEntryUrl2
, delegate()->found_namespace_entry_url_
);
1087 EXPECT_TRUE(delegate()->found_fallback_entry_
.IsFallback());
1091 // BasicFindMainInterceptResponse -------------------------------
1093 void BasicFindMainInterceptResponseInDatabase() {
1094 BasicFindMainInterceptResponse(true);
1097 void BasicFindMainInterceptResponseInWorkingSet() {
1098 BasicFindMainInterceptResponse(false);
1101 void BasicFindMainInterceptResponse(bool drop_from_working_set
) {
1102 PushNextTask(base::Bind(
1103 &AppCacheStorageImplTest::Verify_BasicFindMainInterceptResponse
,
1104 base::Unretained(this)));
1106 // Setup some preconditions. Create a complete cache with an
1107 // intercept namespace and entry.
1108 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
1109 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::INTERCEPT
, 1));
1110 cache_
->AddEntry(kEntryUrl2
, AppCacheEntry(AppCacheEntry::INTERCEPT
, 2));
1111 cache_
->intercept_namespaces_
.push_back(
1112 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE
, kInterceptNamespace2
,
1113 kEntryUrl2
, false));
1114 cache_
->intercept_namespaces_
.push_back(
1115 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE
, kInterceptNamespace
,
1117 AppCacheDatabase::CacheRecord cache_record
;
1118 std::vector
<AppCacheDatabase::EntryRecord
> entries
;
1119 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1120 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1121 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1122 cache_
->ToDatabaseRecords(group_
.get(),
1129 std::vector
<AppCacheDatabase::EntryRecord
>::const_iterator iter
=
1131 while (iter
!= entries
.end()) {
1132 // MakeCacheAndGroup has inserted the default entry record already
1133 if (iter
->url
!= kDefaultEntryUrl
)
1134 EXPECT_TRUE(database()->InsertEntry(&(*iter
)));
1138 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts
));
1139 EXPECT_TRUE(database()->InsertOnlineWhiteListRecords(whitelists
));
1140 if (drop_from_working_set
) {
1141 EXPECT_TRUE(cache_
->HasOneRef());
1143 EXPECT_TRUE(group_
->HasOneRef());
1147 // Conduct the test. The test url is in both intercept namespaces,
1148 // but should match the longer of the two.
1149 storage()->FindResponseForMainRequest(
1150 kInterceptTestUrl
, GURL(), delegate());
1151 EXPECT_NE(kInterceptTestUrl
, delegate()->found_url_
);
1154 void Verify_BasicFindMainInterceptResponse() {
1155 EXPECT_EQ(kInterceptTestUrl
, delegate()->found_url_
);
1156 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1157 EXPECT_EQ(1, delegate()->found_cache_id_
);
1158 EXPECT_EQ(2, delegate()->found_group_id_
);
1159 EXPECT_EQ(2, delegate()->found_entry_
.response_id());
1160 EXPECT_TRUE(delegate()->found_entry_
.IsIntercept());
1161 EXPECT_EQ(kEntryUrl2
, delegate()->found_namespace_entry_url_
);
1162 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1166 // FindInterceptPatternMatch ----------------------------------------
1168 void FindInterceptPatternMatchInDatabase() {
1169 FindInterceptPatternMatch(true);
1172 void FindInterceptPatternMatchInWorkingSet() {
1173 FindInterceptPatternMatch(false);
1176 void FindInterceptPatternMatch(bool drop_from_working_set
) {
1177 // Setup some preconditions. Create a complete cache with an
1178 // pattern matching intercept namespace and entry.
1179 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
1180 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::INTERCEPT
, 1));
1181 cache_
->intercept_namespaces_
.push_back(
1182 AppCacheNamespace(APPCACHE_INTERCEPT_NAMESPACE
,
1183 kInterceptPatternNamespace
, kEntryUrl
, true));
1184 AppCacheDatabase::CacheRecord cache_record
;
1185 std::vector
<AppCacheDatabase::EntryRecord
> entries
;
1186 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1187 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1188 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1189 cache_
->ToDatabaseRecords(group_
.get(),
1196 std::vector
<AppCacheDatabase::EntryRecord
>::const_iterator iter
=
1198 while (iter
!= entries
.end()) {
1199 // MakeCacheAndGroup has inserted the default entry record already
1200 if (iter
->url
!= kDefaultEntryUrl
)
1201 EXPECT_TRUE(database()->InsertEntry(&(*iter
)));
1205 EXPECT_TRUE(database()->InsertNamespaceRecords(intercepts
));
1206 if (drop_from_working_set
) {
1207 EXPECT_TRUE(cache_
->HasOneRef());
1209 EXPECT_TRUE(group_
->HasOneRef());
1213 // First test something that does not match the pattern.
1214 PushNextTask(base::Bind(
1215 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchNegative
,
1216 base::Unretained(this)));
1217 storage()->FindResponseForMainRequest(
1218 kInterceptPatternTestNegativeUrl
, GURL(), delegate());
1219 EXPECT_EQ(GURL(), delegate()->found_url_
); // Is always async.
1222 void Verify_FindInterceptPatternMatchNegative() {
1223 EXPECT_EQ(kInterceptPatternTestNegativeUrl
, delegate()->found_url_
);
1224 EXPECT_TRUE(delegate()->found_manifest_url_
.is_empty());
1225 EXPECT_EQ(kAppCacheNoCacheId
, delegate()->found_cache_id_
);
1226 EXPECT_EQ(kAppCacheNoResponseId
, delegate()->found_entry_
.response_id());
1227 EXPECT_EQ(kAppCacheNoResponseId
,
1228 delegate()->found_fallback_entry_
.response_id());
1229 EXPECT_TRUE(delegate()->found_namespace_entry_url_
.is_empty());
1230 EXPECT_EQ(0, delegate()->found_entry_
.types());
1231 EXPECT_EQ(0, delegate()->found_fallback_entry_
.types());
1233 // Then test something that matches.
1234 PushNextTask(base::Bind(
1235 &AppCacheStorageImplTest::Verify_FindInterceptPatternMatchPositive
,
1236 base::Unretained(this)));
1237 storage()->FindResponseForMainRequest(
1238 kInterceptPatternTestPositiveUrl
, GURL(), delegate());
1241 void Verify_FindInterceptPatternMatchPositive() {
1242 EXPECT_EQ(kInterceptPatternTestPositiveUrl
, delegate()->found_url_
);
1243 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1244 EXPECT_EQ(1, delegate()->found_cache_id_
);
1245 EXPECT_EQ(2, delegate()->found_group_id_
);
1246 EXPECT_EQ(1, delegate()->found_entry_
.response_id());
1247 EXPECT_TRUE(delegate()->found_entry_
.IsIntercept());
1248 EXPECT_EQ(kEntryUrl
, delegate()->found_namespace_entry_url_
);
1249 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1253 // FindFallbackPatternMatch -------------------------------
1255 void FindFallbackPatternMatchInDatabase() {
1256 FindFallbackPatternMatch(true);
1259 void FindFallbackPatternMatchInWorkingSet() {
1260 FindFallbackPatternMatch(false);
1263 void FindFallbackPatternMatch(bool drop_from_working_set
) {
1264 // Setup some preconditions. Create a complete cache with a
1265 // pattern matching fallback namespace and entry.
1266 MakeCacheAndGroup(kManifestUrl
, 2, 1, true);
1267 cache_
->AddEntry(kEntryUrl
, AppCacheEntry(AppCacheEntry::FALLBACK
, 1));
1268 cache_
->fallback_namespaces_
.push_back(
1269 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1270 kFallbackPatternNamespace
, kEntryUrl
, true));
1271 AppCacheDatabase::CacheRecord cache_record
;
1272 std::vector
<AppCacheDatabase::EntryRecord
> entries
;
1273 std::vector
<AppCacheDatabase::NamespaceRecord
> intercepts
;
1274 std::vector
<AppCacheDatabase::NamespaceRecord
> fallbacks
;
1275 std::vector
<AppCacheDatabase::OnlineWhiteListRecord
> whitelists
;
1276 cache_
->ToDatabaseRecords(group_
.get(),
1283 std::vector
<AppCacheDatabase::EntryRecord
>::const_iterator iter
=
1285 while (iter
!= entries
.end()) {
1286 // MakeCacheAndGroup has inserted the default entry record already.
1287 if (iter
->url
!= kDefaultEntryUrl
)
1288 EXPECT_TRUE(database()->InsertEntry(&(*iter
)));
1292 EXPECT_TRUE(database()->InsertNamespaceRecords(fallbacks
));
1293 if (drop_from_working_set
) {
1294 EXPECT_TRUE(cache_
->HasOneRef());
1296 EXPECT_TRUE(group_
->HasOneRef());
1300 // First test something that does not match the pattern.
1301 PushNextTask(base::Bind(
1302 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchNegative
,
1303 base::Unretained(this)));
1304 storage()->FindResponseForMainRequest(
1305 kFallbackPatternTestNegativeUrl
, GURL(), delegate());
1306 EXPECT_EQ(GURL(), delegate()->found_url_
); // Is always async.
1309 void Verify_FindFallbackPatternMatchNegative() {
1310 EXPECT_EQ(kFallbackPatternTestNegativeUrl
, delegate()->found_url_
);
1311 EXPECT_TRUE(delegate()->found_manifest_url_
.is_empty());
1312 EXPECT_EQ(kAppCacheNoCacheId
, delegate()->found_cache_id_
);
1313 EXPECT_EQ(kAppCacheNoResponseId
, delegate()->found_entry_
.response_id());
1314 EXPECT_EQ(kAppCacheNoResponseId
,
1315 delegate()->found_fallback_entry_
.response_id());
1316 EXPECT_TRUE(delegate()->found_namespace_entry_url_
.is_empty());
1317 EXPECT_EQ(0, delegate()->found_entry_
.types());
1318 EXPECT_EQ(0, delegate()->found_fallback_entry_
.types());
1320 // Then test something that matches.
1321 PushNextTask(base::Bind(
1322 &AppCacheStorageImplTest::Verify_FindFallbackPatternMatchPositive
,
1323 base::Unretained(this)));
1324 storage()->FindResponseForMainRequest(
1325 kFallbackPatternTestPositiveUrl
, GURL(), delegate());
1328 void Verify_FindFallbackPatternMatchPositive() {
1329 EXPECT_EQ(kFallbackPatternTestPositiveUrl
, delegate()->found_url_
);
1330 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1331 EXPECT_EQ(1, delegate()->found_cache_id_
);
1332 EXPECT_EQ(2, delegate()->found_group_id_
);
1333 EXPECT_EQ(1, delegate()->found_fallback_entry_
.response_id());
1334 EXPECT_TRUE(delegate()->found_fallback_entry_
.IsFallback());
1335 EXPECT_EQ(kEntryUrl
, delegate()->found_namespace_entry_url_
);
1336 EXPECT_FALSE(delegate()->found_entry_
.has_response_id());
1340 // FindMainResponseWithMultipleHits -------------------------------
1342 void FindMainResponseWithMultipleHits() {
1343 PushNextTask(base::Bind(
1344 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits
,
1345 base::Unretained(this)));
1347 // Setup some preconditions, create a few caches with an identical set
1348 // of entries and fallback namespaces. Only the last one remains in
1349 // the working set to simulate appearing as "in use".
1350 MakeMultipleHitCacheAndGroup(kManifestUrl
, 1);
1351 MakeMultipleHitCacheAndGroup(kManifestUrl2
, 2);
1352 MakeMultipleHitCacheAndGroup(kManifestUrl3
, 3);
1354 // Conduct the test, we should find the response from the last cache
1355 // since it's "in use".
1356 storage()->FindResponseForMainRequest(kEntryUrl
, GURL(), delegate());
1357 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
1360 void MakeMultipleHitCacheAndGroup(const GURL
& manifest_url
, int id
) {
1361 MakeCacheAndGroup(manifest_url
, id
, id
, true);
1362 AppCacheDatabase::EntryRecord entry_record
;
1364 // Add an entry for kEntryUrl
1365 entry_record
.cache_id
= id
;
1366 entry_record
.url
= kEntryUrl
;
1367 entry_record
.flags
= AppCacheEntry::EXPLICIT
;
1368 entry_record
.response_id
= id
;
1369 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1372 AppCacheEntry(entry_record
.flags
, entry_record
.response_id
));
1374 // Add an entry for the manifestUrl
1375 entry_record
.cache_id
= id
;
1376 entry_record
.url
= manifest_url
;
1377 entry_record
.flags
= AppCacheEntry::MANIFEST
;
1378 entry_record
.response_id
= id
+ kManifestEntryIdOffset
;
1379 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1382 AppCacheEntry(entry_record
.flags
, entry_record
.response_id
));
1384 // Add a fallback entry and namespace
1385 entry_record
.cache_id
= id
;
1386 entry_record
.url
= kEntryUrl2
;
1387 entry_record
.flags
= AppCacheEntry::FALLBACK
;
1388 entry_record
.response_id
= id
+ kFallbackEntryIdOffset
;
1389 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1392 AppCacheEntry(entry_record
.flags
, entry_record
.response_id
));
1393 AppCacheDatabase::NamespaceRecord fallback_namespace_record
;
1394 fallback_namespace_record
.cache_id
= id
;
1395 fallback_namespace_record
.namespace_
.target_url
= entry_record
.url
;
1396 fallback_namespace_record
.namespace_
.namespace_url
= kFallbackNamespace
;
1397 fallback_namespace_record
.origin
= manifest_url
.GetOrigin();
1398 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record
));
1399 cache_
->fallback_namespaces_
.push_back(
1400 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1406 void Verify_FindMainResponseWithMultipleHits() {
1407 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
1408 EXPECT_EQ(kManifestUrl3
, delegate()->found_manifest_url_
);
1409 EXPECT_EQ(3, delegate()->found_cache_id_
);
1410 EXPECT_EQ(3, delegate()->found_group_id_
);
1411 EXPECT_EQ(3, delegate()->found_entry_
.response_id());
1412 EXPECT_TRUE(delegate()->found_entry_
.IsExplicit());
1413 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1415 // Conduct another test preferring kManifestUrl
1416 delegate_
.reset(new MockStorageDelegate(this));
1417 PushNextTask(base::Bind(
1418 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits2
,
1419 base::Unretained(this)));
1420 storage()->FindResponseForMainRequest(kEntryUrl
, kManifestUrl
, delegate());
1421 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
1424 void Verify_FindMainResponseWithMultipleHits2() {
1425 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
1426 EXPECT_EQ(kManifestUrl
, delegate()->found_manifest_url_
);
1427 EXPECT_EQ(1, delegate()->found_cache_id_
);
1428 EXPECT_EQ(1, delegate()->found_group_id_
);
1429 EXPECT_EQ(1, delegate()->found_entry_
.response_id());
1430 EXPECT_TRUE(delegate()->found_entry_
.IsExplicit());
1431 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1433 // Conduct the another test preferring kManifestUrl2
1434 delegate_
.reset(new MockStorageDelegate(this));
1435 PushNextTask(base::Bind(
1436 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits3
,
1437 base::Unretained(this)));
1438 storage()->FindResponseForMainRequest(kEntryUrl
, kManifestUrl2
, delegate());
1439 EXPECT_NE(kEntryUrl
, delegate()->found_url_
);
1442 void Verify_FindMainResponseWithMultipleHits3() {
1443 EXPECT_EQ(kEntryUrl
, delegate()->found_url_
);
1444 EXPECT_EQ(kManifestUrl2
, delegate()->found_manifest_url_
);
1445 EXPECT_EQ(2, delegate()->found_cache_id_
);
1446 EXPECT_EQ(2, delegate()->found_group_id_
);
1447 EXPECT_EQ(2, delegate()->found_entry_
.response_id());
1448 EXPECT_TRUE(delegate()->found_entry_
.IsExplicit());
1449 EXPECT_FALSE(delegate()->found_fallback_entry_
.has_response_id());
1451 // Conduct another test with no preferred manifest that hits the fallback.
1452 delegate_
.reset(new MockStorageDelegate(this));
1453 PushNextTask(base::Bind(
1454 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits4
,
1455 base::Unretained(this)));
1456 storage()->FindResponseForMainRequest(
1457 kFallbackTestUrl
, GURL(), delegate());
1458 EXPECT_NE(kFallbackTestUrl
, delegate()->found_url_
);
1461 void Verify_FindMainResponseWithMultipleHits4() {
1462 EXPECT_EQ(kFallbackTestUrl
, delegate()->found_url_
);
1463 EXPECT_EQ(kManifestUrl3
, delegate()->found_manifest_url_
);
1464 EXPECT_EQ(3, delegate()->found_cache_id_
);
1465 EXPECT_EQ(3, delegate()->found_group_id_
);
1466 EXPECT_FALSE(delegate()->found_entry_
.has_response_id());
1467 EXPECT_EQ(3 + kFallbackEntryIdOffset
,
1468 delegate()->found_fallback_entry_
.response_id());
1469 EXPECT_TRUE(delegate()->found_fallback_entry_
.IsFallback());
1470 EXPECT_EQ(kEntryUrl2
, delegate()->found_namespace_entry_url_
);
1472 // Conduct another test preferring kManifestUrl2 that hits the fallback.
1473 delegate_
.reset(new MockStorageDelegate(this));
1474 PushNextTask(base::Bind(
1475 &AppCacheStorageImplTest::Verify_FindMainResponseWithMultipleHits5
,
1476 base::Unretained(this)));
1477 storage()->FindResponseForMainRequest(
1478 kFallbackTestUrl
, kManifestUrl2
, delegate());
1479 EXPECT_NE(kFallbackTestUrl
, delegate()->found_url_
);
1482 void Verify_FindMainResponseWithMultipleHits5() {
1483 EXPECT_EQ(kFallbackTestUrl
, delegate()->found_url_
);
1484 EXPECT_EQ(kManifestUrl2
, delegate()->found_manifest_url_
);
1485 EXPECT_EQ(2, delegate()->found_cache_id_
);
1486 EXPECT_EQ(2, delegate()->found_group_id_
);
1487 EXPECT_FALSE(delegate()->found_entry_
.has_response_id());
1488 EXPECT_EQ(2 + kFallbackEntryIdOffset
,
1489 delegate()->found_fallback_entry_
.response_id());
1490 EXPECT_TRUE(delegate()->found_fallback_entry_
.IsFallback());
1491 EXPECT_EQ(kEntryUrl2
, delegate()->found_namespace_entry_url_
);
1496 // FindMainResponseExclusions -------------------------------
1498 void FindMainResponseExclusionsInDatabase() {
1499 FindMainResponseExclusions(true);
1502 void FindMainResponseExclusionsInWorkingSet() {
1503 FindMainResponseExclusions(false);
1506 void FindMainResponseExclusions(bool drop_from_working_set
) {
1507 // Setup some preconditions. Create a complete cache with a
1508 // foreign entry, an online namespace, and a second online
1509 // namespace nested within a fallback namespace.
1510 MakeCacheAndGroup(kManifestUrl
, 1, 1, true);
1511 cache_
->AddEntry(kEntryUrl
,
1512 AppCacheEntry(AppCacheEntry::EXPLICIT
| AppCacheEntry::FOREIGN
, 1));
1513 cache_
->AddEntry(kEntryUrl2
, AppCacheEntry(AppCacheEntry::FALLBACK
, 2));
1514 cache_
->fallback_namespaces_
.push_back(
1515 AppCacheNamespace(APPCACHE_FALLBACK_NAMESPACE
,
1519 cache_
->online_whitelist_namespaces_
.push_back(
1520 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE
, kOnlineNamespace
,
1522 cache_
->online_whitelist_namespaces_
.push_back(
1523 AppCacheNamespace(APPCACHE_NETWORK_NAMESPACE
,
1524 kOnlineNamespaceWithinFallback
, GURL(), false));
1526 AppCacheDatabase::EntryRecord entry_record
;
1527 entry_record
.cache_id
= 1;
1528 entry_record
.url
= kEntryUrl
;
1529 entry_record
.flags
= AppCacheEntry::EXPLICIT
| AppCacheEntry::FOREIGN
;
1530 entry_record
.response_id
= 1;
1531 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1532 AppCacheDatabase::OnlineWhiteListRecord whitelist_record
;
1533 whitelist_record
.cache_id
= 1;
1534 whitelist_record
.namespace_url
= kOnlineNamespace
;
1535 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record
));
1536 AppCacheDatabase::NamespaceRecord fallback_namespace_record
;
1537 fallback_namespace_record
.cache_id
= 1;
1538 fallback_namespace_record
.namespace_
.target_url
= kEntryUrl2
;
1539 fallback_namespace_record
.namespace_
.namespace_url
= kFallbackNamespace
;
1540 fallback_namespace_record
.origin
= kManifestUrl
.GetOrigin();
1541 EXPECT_TRUE(database()->InsertNamespace(&fallback_namespace_record
));
1542 whitelist_record
.cache_id
= 1;
1543 whitelist_record
.namespace_url
= kOnlineNamespaceWithinFallback
;
1544 EXPECT_TRUE(database()->InsertOnlineWhiteList(&whitelist_record
));
1545 if (drop_from_working_set
) {
1550 // We should not find anything for the foreign entry.
1551 PushNextTask(base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound
,
1552 base::Unretained(this), kEntryUrl
, 1));
1553 storage()->FindResponseForMainRequest(kEntryUrl
, GURL(), delegate());
1556 void Verify_ExclusionNotFound(GURL expected_url
, int phase
) {
1557 EXPECT_EQ(expected_url
, delegate()->found_url_
);
1558 EXPECT_TRUE(delegate()->found_manifest_url_
.is_empty());
1559 EXPECT_EQ(kAppCacheNoCacheId
, delegate()->found_cache_id_
);
1560 EXPECT_EQ(0, delegate()->found_group_id_
);
1561 EXPECT_EQ(kAppCacheNoResponseId
, delegate()->found_entry_
.response_id());
1562 EXPECT_EQ(kAppCacheNoResponseId
,
1563 delegate()->found_fallback_entry_
.response_id());
1564 EXPECT_TRUE(delegate()->found_namespace_entry_url_
.is_empty());
1565 EXPECT_EQ(0, delegate()->found_entry_
.types());
1566 EXPECT_EQ(0, delegate()->found_fallback_entry_
.types());
1569 // We should not find anything for the online namespace.
1571 base::Bind(&AppCacheStorageImplTest::Verify_ExclusionNotFound
,
1572 base::Unretained(this), kOnlineNamespace
, 2));
1573 storage()->FindResponseForMainRequest(
1574 kOnlineNamespace
, GURL(), delegate());
1578 // We should not find anything for the online namespace nested within
1579 // the fallback namespace.
1580 PushNextTask(base::Bind(
1581 &AppCacheStorageImplTest::Verify_ExclusionNotFound
,
1582 base::Unretained(this), kOnlineNamespaceWithinFallback
, 3));
1583 storage()->FindResponseForMainRequest(
1584 kOnlineNamespaceWithinFallback
, GURL(), delegate());
1591 // Reinitialize -------------------------------
1592 // These tests are somewhat of a system integration test.
1593 // They rely on running a mock http server on our IO thread,
1594 // and involves other appcache classes to get some code
1595 // coverage thruout when Reinitialize happens.
1597 class MockServiceObserver
: public AppCacheServiceImpl::Observer
{
1599 explicit MockServiceObserver(AppCacheStorageImplTest
* test
)
1602 virtual void OnServiceReinitialized(
1603 AppCacheStorageReference
* old_storage_ref
) OVERRIDE
{
1604 observed_old_storage_
= old_storage_ref
;
1605 test_
->ScheduleNextTask();
1608 scoped_refptr
<AppCacheStorageReference
> observed_old_storage_
;
1609 AppCacheStorageImplTest
* test_
;
1612 class MockAppCacheFrontend
: public AppCacheFrontend
{
1614 MockAppCacheFrontend() : error_event_was_raised_(false) {}
1616 virtual void OnCacheSelected(
1617 int host_id
, const AppCacheInfo
& info
) OVERRIDE
{}
1618 virtual void OnStatusChanged(const std::vector
<int>& host_ids
,
1619 AppCacheStatus status
) OVERRIDE
{}
1620 virtual void OnEventRaised(const std::vector
<int>& host_ids
,
1621 AppCacheEventID event_id
) OVERRIDE
{}
1622 virtual void OnProgressEventRaised(
1623 const std::vector
<int>& host_ids
,
1625 int num_total
, int num_complete
) OVERRIDE
{}
1626 virtual void OnErrorEventRaised(const std::vector
<int>& host_ids
,
1627 const AppCacheErrorDetails
& details
)
1629 error_event_was_raised_
= true;
1631 virtual void OnLogMessage(int host_id
, AppCacheLogLevel log_level
,
1632 const std::string
& message
) OVERRIDE
{}
1633 virtual void OnContentBlocked(
1634 int host_id
, const GURL
& manifest_url
) OVERRIDE
{}
1636 bool error_event_was_raised_
;
1639 enum ReinitTestCase
{
1640 CORRUPT_CACHE_ON_INSTALL
,
1641 CORRUPT_CACHE_ON_LOAD_EXISTING
,
1642 CORRUPT_SQL_ON_INSTALL
1645 void Reinitialize1() {
1646 // Recover from a corrupt disk cache discovered while
1647 // installing a new appcache.
1648 Reinitialize(CORRUPT_CACHE_ON_INSTALL
);
1651 void Reinitialize2() {
1652 // Recover from a corrupt disk cache discovered while
1653 // trying to load a resource from an existing appcache.
1654 Reinitialize(CORRUPT_CACHE_ON_LOAD_EXISTING
);
1657 void Reinitialize3() {
1658 // Recover from a corrupt sql database discovered while
1659 // installing a new appcache.
1660 Reinitialize(CORRUPT_SQL_ON_INSTALL
);
1663 void Reinitialize(ReinitTestCase test_case
) {
1664 // Unlike all of the other tests, this one actually read/write files.
1665 ASSERT_TRUE(temp_directory_
.CreateUniqueTempDir());
1667 AppCacheDatabase
db(temp_directory_
.path().AppendASCII("Index"));
1668 EXPECT_TRUE(db
.LazyOpen(true));
1670 if (test_case
== CORRUPT_CACHE_ON_INSTALL
||
1671 test_case
== CORRUPT_CACHE_ON_LOAD_EXISTING
) {
1672 // Create a corrupt/unopenable disk_cache index file.
1673 const std::string
kCorruptData("deadbeef");
1674 base::FilePath disk_cache_directory
=
1675 temp_directory_
.path().AppendASCII("Cache");
1676 ASSERT_TRUE(base::CreateDirectory(disk_cache_directory
));
1677 base::FilePath index_file
= disk_cache_directory
.AppendASCII("index");
1678 EXPECT_EQ(static_cast<int>(kCorruptData
.length()),
1680 index_file
, kCorruptData
.data(), kCorruptData
.length()));
1683 // Create records for a degenerate cached manifest that only contains
1684 // one entry for the manifest file resource.
1685 if (test_case
== CORRUPT_CACHE_ON_LOAD_EXISTING
) {
1686 AppCacheDatabase
db(temp_directory_
.path().AppendASCII("Index"));
1687 GURL manifest_url
= MockHttpServer::GetMockUrl("manifest");
1689 AppCacheDatabase::GroupRecord group_record
;
1690 group_record
.group_id
= 1;
1691 group_record
.manifest_url
= manifest_url
;
1692 group_record
.origin
= manifest_url
.GetOrigin();
1693 EXPECT_TRUE(db
.InsertGroup(&group_record
));
1694 AppCacheDatabase::CacheRecord cache_record
;
1695 cache_record
.cache_id
= 1;
1696 cache_record
.group_id
= 1;
1697 cache_record
.online_wildcard
= false;
1698 cache_record
.update_time
= kZeroTime
;
1699 cache_record
.cache_size
= kDefaultEntrySize
;
1700 EXPECT_TRUE(db
.InsertCache(&cache_record
));
1701 AppCacheDatabase::EntryRecord entry_record
;
1702 entry_record
.cache_id
= 1;
1703 entry_record
.url
= manifest_url
;
1704 entry_record
.flags
= AppCacheEntry::MANIFEST
;
1705 entry_record
.response_id
= 1;
1706 entry_record
.response_size
= kDefaultEntrySize
;
1707 EXPECT_TRUE(db
.InsertEntry(&entry_record
));
1710 // Recreate the service to point at the db and corruption on disk.
1711 service_
.reset(new AppCacheServiceImpl(NULL
));
1712 service_
->set_request_context(io_thread
->request_context());
1713 service_
->Initialize(
1714 temp_directory_
.path(),
1715 db_thread
->message_loop_proxy().get(),
1716 db_thread
->message_loop_proxy().get());
1717 mock_quota_manager_proxy_
= new MockQuotaManagerProxy();
1718 service_
->quota_manager_proxy_
= mock_quota_manager_proxy_
;
1719 delegate_
.reset(new MockStorageDelegate(this));
1721 // Additional setup to observe reinitailize happens.
1722 observer_
.reset(new MockServiceObserver(this));
1723 service_
->AddObserver(observer_
.get());
1725 // We continue after the init task is complete including the callback
1726 // on the current thread.
1727 FlushDbThreadTasks();
1728 base::MessageLoop::current()->PostTask(
1730 base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize
,
1731 base::Unretained(this),
1735 void Continue_Reinitialize(ReinitTestCase test_case
) {
1736 const int kMockProcessId
= 1;
1737 backend_
.reset(new AppCacheBackendImpl
);
1738 backend_
->Initialize(service_
.get(), &frontend_
, kMockProcessId
);
1740 if (test_case
== CORRUPT_SQL_ON_INSTALL
) {
1741 // Break the db file
1742 EXPECT_FALSE(database()->was_corruption_detected());
1743 ASSERT_TRUE(sql::test::CorruptSizeInHeader(
1744 temp_directory_
.path().AppendASCII("Index")));
1747 if (test_case
== CORRUPT_CACHE_ON_INSTALL
||
1748 test_case
== CORRUPT_SQL_ON_INSTALL
) {
1749 // Try to create a new appcache, the resulting update job will
1750 // eventually fail when it gets to disk cache initialization.
1751 backend_
->RegisterHost(1);
1752 AppCacheHost
* host1
= backend_
->GetHost(1);
1753 const GURL
kEmptyPageUrl(MockHttpServer::GetMockUrl("empty.html"));
1754 host1
->first_party_url_
= kEmptyPageUrl
;
1755 host1
->SelectCache(kEmptyPageUrl
,
1757 MockHttpServer::GetMockUrl("manifest"));
1759 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING
, test_case
);
1760 // Try to access the existing cache manifest.
1761 // The URLRequestJob will eventually fail when it gets to disk
1762 // cache initialization.
1763 backend_
->RegisterHost(2);
1764 AppCacheHost
* host2
= backend_
->GetHost(2);
1765 GURL manifest_url
= MockHttpServer::GetMockUrl("manifest");
1766 request_
= service()->request_context()->CreateRequest(
1767 manifest_url
, net::DEFAULT_PRIORITY
, NULL
, NULL
);
1768 AppCacheInterceptor::SetExtraRequestInfo(
1769 request_
.get(), service_
.get(),
1770 backend_
->process_id(), host2
->host_id(),
1771 ResourceType::MAIN_FRAME
);
1775 PushNextTask(base::Bind(
1776 &AppCacheStorageImplTest::Verify_Reinitialized
,
1777 base::Unretained(this),
1781 void Verify_Reinitialized(ReinitTestCase test_case
) {
1782 // Verify we got notified of reinit and a new storage instance is created,
1783 // and that the old data has been deleted.
1784 EXPECT_TRUE(observer_
->observed_old_storage_
.get());
1785 EXPECT_TRUE(observer_
->observed_old_storage_
->storage() != storage());
1786 EXPECT_FALSE(PathExists(
1787 temp_directory_
.path().AppendASCII("Cache").AppendASCII("index")));
1788 EXPECT_FALSE(PathExists(
1789 temp_directory_
.path().AppendASCII("Index")));
1791 if (test_case
== CORRUPT_SQL_ON_INSTALL
) {
1792 AppCacheStorageImpl
* storage
= static_cast<AppCacheStorageImpl
*>(
1793 observer_
->observed_old_storage_
->storage());
1794 EXPECT_TRUE(storage
->database_
->was_corruption_detected());
1797 // Verify that the hosts saw appropriate events.
1798 if (test_case
== CORRUPT_CACHE_ON_INSTALL
||
1799 test_case
== CORRUPT_SQL_ON_INSTALL
) {
1800 EXPECT_TRUE(frontend_
.error_event_was_raised_
);
1801 AppCacheHost
* host1
= backend_
->GetHost(1);
1802 EXPECT_FALSE(host1
->associated_cache());
1803 EXPECT_FALSE(host1
->group_being_updated_
);
1804 EXPECT_TRUE(host1
->disabled_storage_reference_
.get());
1806 ASSERT_EQ(CORRUPT_CACHE_ON_LOAD_EXISTING
, test_case
);
1807 AppCacheHost
* host2
= backend_
->GetHost(2);
1808 EXPECT_EQ(1, host2
->main_resource_cache_
->cache_id());
1809 EXPECT_TRUE(host2
->disabled_storage_reference_
.get());
1812 // Cleanup and claim victory.
1813 service_
->RemoveObserver(observer_
.get());
1820 // Test case helpers --------------------------------------------------
1822 AppCacheServiceImpl
* service() {
1823 return service_
.get();
1826 AppCacheStorageImpl
* storage() {
1827 return static_cast<AppCacheStorageImpl
*>(service()->storage());
1830 AppCacheDatabase
* database() {
1831 return storage()->database_
;
1834 MockStorageDelegate
* delegate() {
1835 return delegate_
.get();
1838 void MakeCacheAndGroup(
1839 const GURL
& manifest_url
, int64 group_id
, int64 cache_id
,
1840 bool add_to_database
) {
1841 AppCacheEntry
default_entry(
1842 AppCacheEntry::EXPLICIT
, cache_id
+ kDefaultEntryIdOffset
,
1844 group_
= new AppCacheGroup(storage(), manifest_url
, group_id
);
1845 cache_
= new AppCache(storage(), cache_id
);
1846 cache_
->AddEntry(kDefaultEntryUrl
, default_entry
);
1847 cache_
->set_complete(true);
1848 group_
->AddCache(cache_
.get());
1849 if (add_to_database
) {
1850 AppCacheDatabase::GroupRecord group_record
;
1851 group_record
.group_id
= group_id
;
1852 group_record
.manifest_url
= manifest_url
;
1853 group_record
.origin
= manifest_url
.GetOrigin();
1854 EXPECT_TRUE(database()->InsertGroup(&group_record
));
1855 AppCacheDatabase::CacheRecord cache_record
;
1856 cache_record
.cache_id
= cache_id
;
1857 cache_record
.group_id
= group_id
;
1858 cache_record
.online_wildcard
= false;
1859 cache_record
.update_time
= kZeroTime
;
1860 cache_record
.cache_size
= kDefaultEntrySize
;
1861 EXPECT_TRUE(database()->InsertCache(&cache_record
));
1862 AppCacheDatabase::EntryRecord entry_record
;
1863 entry_record
.cache_id
= cache_id
;
1864 entry_record
.url
= kDefaultEntryUrl
;
1865 entry_record
.flags
= default_entry
.types();
1866 entry_record
.response_id
= default_entry
.response_id();
1867 entry_record
.response_size
= default_entry
.response_size();
1868 EXPECT_TRUE(database()->InsertEntry(&entry_record
));
1870 storage()->usage_map_
[manifest_url
.GetOrigin()] =
1871 default_entry
.response_size();
1875 // Data members --------------------------------------------------
1877 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
1878 std::stack
<base::Closure
> task_stack_
;
1879 scoped_ptr
<AppCacheServiceImpl
> service_
;
1880 scoped_ptr
<MockStorageDelegate
> delegate_
;
1881 scoped_refptr
<MockQuotaManagerProxy
> mock_quota_manager_proxy_
;
1882 scoped_refptr
<AppCacheGroup
> group_
;
1883 scoped_refptr
<AppCache
> cache_
;
1884 scoped_refptr
<AppCache
> cache2_
;
1886 // Specifically for the Reinitalize test.
1887 base::ScopedTempDir temp_directory_
;
1888 scoped_ptr
<MockServiceObserver
> observer_
;
1889 MockAppCacheFrontend frontend_
;
1890 scoped_ptr
<AppCacheBackendImpl
> backend_
;
1891 scoped_ptr
<net::URLRequest
> request_
;
1895 TEST_F(AppCacheStorageImplTest
, LoadCache_Miss
) {
1896 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_Miss
);
1899 TEST_F(AppCacheStorageImplTest
, LoadCache_NearHit
) {
1900 RunTestOnIOThread(&AppCacheStorageImplTest::LoadCache_NearHit
);
1903 TEST_F(AppCacheStorageImplTest
, CreateGroupInEmptyOrigin
) {
1904 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInEmptyOrigin
);
1907 TEST_F(AppCacheStorageImplTest
, CreateGroupInPopulatedOrigin
) {
1908 RunTestOnIOThread(&AppCacheStorageImplTest::CreateGroupInPopulatedOrigin
);
1911 TEST_F(AppCacheStorageImplTest
, LoadGroupAndCache_FarHit
) {
1912 RunTestOnIOThread(&AppCacheStorageImplTest::LoadGroupAndCache_FarHit
);
1915 TEST_F(AppCacheStorageImplTest
, StoreNewGroup
) {
1916 RunTestOnIOThread(&AppCacheStorageImplTest::StoreNewGroup
);
1919 TEST_F(AppCacheStorageImplTest
, StoreExistingGroup
) {
1920 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroup
);
1923 TEST_F(AppCacheStorageImplTest
, StoreExistingGroupExistingCache
) {
1924 RunTestOnIOThread(&AppCacheStorageImplTest::StoreExistingGroupExistingCache
);
1927 TEST_F(AppCacheStorageImplTest
, FailStoreGroup
) {
1928 RunTestOnIOThread(&AppCacheStorageImplTest::FailStoreGroup
);
1931 TEST_F(AppCacheStorageImplTest
, MakeGroupObsolete
) {
1932 RunTestOnIOThread(&AppCacheStorageImplTest::MakeGroupObsolete
);
1935 TEST_F(AppCacheStorageImplTest
, MarkEntryAsForeign
) {
1936 RunTestOnIOThread(&AppCacheStorageImplTest::MarkEntryAsForeign
);
1939 TEST_F(AppCacheStorageImplTest
, MarkEntryAsForeignWithLoadInProgress
) {
1941 &AppCacheStorageImplTest::MarkEntryAsForeignWithLoadInProgress
);
1944 TEST_F(AppCacheStorageImplTest
, FindNoMainResponse
) {
1945 RunTestOnIOThread(&AppCacheStorageImplTest::FindNoMainResponse
);
1948 TEST_F(AppCacheStorageImplTest
, BasicFindMainResponseInDatabase
) {
1950 &AppCacheStorageImplTest::BasicFindMainResponseInDatabase
);
1953 TEST_F(AppCacheStorageImplTest
, BasicFindMainResponseInWorkingSet
) {
1955 &AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet
);
1958 TEST_F(AppCacheStorageImplTest
, BasicFindMainFallbackResponseInDatabase
) {
1960 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase
);
1963 TEST_F(AppCacheStorageImplTest
, BasicFindMainFallbackResponseInWorkingSet
) {
1965 &AppCacheStorageImplTest::BasicFindMainFallbackResponseInWorkingSet
);
1968 TEST_F(AppCacheStorageImplTest
, BasicFindMainInterceptResponseInDatabase
) {
1970 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInDatabase
);
1973 TEST_F(AppCacheStorageImplTest
, BasicFindMainInterceptResponseInWorkingSet
) {
1975 &AppCacheStorageImplTest::BasicFindMainInterceptResponseInWorkingSet
);
1978 TEST_F(AppCacheStorageImplTest
, FindMainResponseWithMultipleHits
) {
1980 &AppCacheStorageImplTest::FindMainResponseWithMultipleHits
);
1983 TEST_F(AppCacheStorageImplTest
, FindMainResponseExclusionsInDatabase
) {
1985 &AppCacheStorageImplTest::FindMainResponseExclusionsInDatabase
);
1988 TEST_F(AppCacheStorageImplTest
, FindMainResponseExclusionsInWorkingSet
) {
1990 &AppCacheStorageImplTest::FindMainResponseExclusionsInWorkingSet
);
1993 TEST_F(AppCacheStorageImplTest
, FindInterceptPatternMatchInWorkingSet
) {
1995 &AppCacheStorageImplTest::FindInterceptPatternMatchInWorkingSet
);
1998 TEST_F(AppCacheStorageImplTest
, FindInterceptPatternMatchInDatabase
) {
2000 &AppCacheStorageImplTest::FindInterceptPatternMatchInDatabase
);
2003 TEST_F(AppCacheStorageImplTest
, FindFallbackPatternMatchInWorkingSet
) {
2005 &AppCacheStorageImplTest::FindFallbackPatternMatchInWorkingSet
);
2008 TEST_F(AppCacheStorageImplTest
, FindFallbackPatternMatchInDatabase
) {
2010 &AppCacheStorageImplTest::FindFallbackPatternMatchInDatabase
);
2013 TEST_F(AppCacheStorageImplTest
, Reinitialize1
) {
2014 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize1
);
2017 TEST_F(AppCacheStorageImplTest
, Reinitialize2
) {
2018 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize2
);
2021 TEST_F(AppCacheStorageImplTest
, Reinitialize3
) {
2022 RunTestOnIOThread(&AppCacheStorageImplTest::Reinitialize3
);
2025 // That's all folks!
2027 } // namespace content