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.
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "content/browser/appcache/appcache.h"
16 #include "content/browser/appcache/appcache_backend_impl.h"
17 #include "content/browser/appcache/appcache_request_handler.h"
18 #include "content/browser/appcache/appcache_url_request_job.h"
19 #include "content/browser/appcache/mock_appcache_policy.h"
20 #include "content/browser/appcache/mock_appcache_service.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/request_priority.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/url_request/url_request.h"
25 #include "net/url_request/url_request_context.h"
26 #include "net/url_request/url_request_error_job.h"
27 #include "net/url_request/url_request_job_factory.h"
28 #include "testing/gtest/include/gtest/gtest.h"
32 static const int kMockProcessId
= 1;
34 class AppCacheRequestHandlerTest
: public testing::Test
{
36 class MockFrontend
: public AppCacheFrontend
{
38 virtual void OnCacheSelected(
39 int host_id
, const AppCacheInfo
& info
) OVERRIDE
{}
41 virtual void OnStatusChanged(const std::vector
<int>& host_ids
,
42 AppCacheStatus status
) OVERRIDE
{}
44 virtual void OnEventRaised(const std::vector
<int>& host_ids
,
45 AppCacheEventID event_id
) OVERRIDE
{}
47 virtual void OnErrorEventRaised(
48 const std::vector
<int>& host_ids
,
49 const AppCacheErrorDetails
& details
) OVERRIDE
{}
51 virtual void OnProgressEventRaised(const std::vector
<int>& host_ids
,
54 int num_complete
) OVERRIDE
{
57 virtual void OnLogMessage(int host_id
,
58 AppCacheLogLevel log_level
,
59 const std::string
& message
) OVERRIDE
{
62 virtual void OnContentBlocked(int host_id
,
63 const GURL
& manifest_url
) OVERRIDE
{}
66 // Helper callback to run a test on our io_thread. The io_thread is spun up
67 // once and reused for all tests.
68 template <class Method
>
69 void MethodWrapper(Method method
) {
74 // Subclasses to simulate particular responses so test cases can
75 // exercise fallback code paths.
77 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
78 virtual void OnResponseStarted(net::URLRequest
* request
) OVERRIDE
{}
79 virtual void OnReadCompleted(net::URLRequest
* request
,
80 int bytes_read
) OVERRIDE
{
84 class MockURLRequestJob
: public net::URLRequestJob
{
86 MockURLRequestJob(net::URLRequest
* request
,
87 net::NetworkDelegate
* network_delegate
,
89 : net::URLRequestJob(request
, network_delegate
),
90 response_code_(response_code
),
91 has_response_info_(false) {}
92 MockURLRequestJob(net::URLRequest
* request
,
93 net::NetworkDelegate
* network_delegate
,
94 const net::HttpResponseInfo
& info
)
95 : net::URLRequestJob(request
, network_delegate
),
96 response_code_(info
.headers
->response_code()),
97 has_response_info_(true),
98 response_info_(info
) {}
101 virtual ~MockURLRequestJob() {}
102 virtual void Start() OVERRIDE
{
103 NotifyHeadersComplete();
105 virtual int GetResponseCode() const OVERRIDE
{
106 return response_code_
;
108 virtual void GetResponseInfo(
109 net::HttpResponseInfo
* info
) OVERRIDE
{
110 if (!has_response_info_
)
112 *info
= response_info_
;
117 bool has_response_info_
;
118 net::HttpResponseInfo response_info_
;
121 class MockURLRequestJobFactory
: public net::URLRequestJobFactory
{
123 MockURLRequestJobFactory() : job_(NULL
) {
126 virtual ~MockURLRequestJobFactory() {
130 void SetJob(net::URLRequestJob
* job
) {
134 virtual net::URLRequestJob
* MaybeCreateJobWithProtocolHandler(
135 const std::string
& scheme
,
136 net::URLRequest
* request
,
137 net::NetworkDelegate
* network_delegate
) const OVERRIDE
{
139 net::URLRequestJob
* temp
= job_
;
143 // Some of these tests trigger UpdateJobs which start URLRequests.
144 // We short circuit those be returning error jobs.
145 return new net::URLRequestErrorJob(request
,
147 net::ERR_INTERNET_DISCONNECTED
);
151 virtual bool IsHandledProtocol(const std::string
& scheme
) const OVERRIDE
{
152 return scheme
== "http";
155 virtual bool IsHandledURL(const GURL
& url
) const OVERRIDE
{
156 return url
.SchemeIs("http");
159 virtual bool IsSafeRedirectTarget(const GURL
& location
) const OVERRIDE
{
164 mutable net::URLRequestJob
* job_
;
167 static void SetUpTestCase() {
168 io_thread_
.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
169 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
170 io_thread_
->StartWithOptions(options
);
173 static void TearDownTestCase() {
174 io_thread_
.reset(NULL
);
177 // Test harness --------------------------------------------------
179 AppCacheRequestHandlerTest() : host_(NULL
) {}
181 template <class Method
>
182 void RunTestOnIOThread(Method method
) {
183 test_finished_event_
.reset(new base::WaitableEvent(false, false));
184 io_thread_
->message_loop()->PostTask(
186 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper
<Method
>,
187 base::Unretained(this), method
));
188 test_finished_event_
->Wait();
192 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
193 mock_service_
.reset(new MockAppCacheService
);
194 mock_service_
->set_request_context(&empty_context_
);
195 mock_policy_
.reset(new MockAppCachePolicy
);
196 mock_service_
->set_appcache_policy(mock_policy_
.get());
197 mock_frontend_
.reset(new MockFrontend
);
198 backend_impl_
.reset(new AppCacheBackendImpl
);
199 backend_impl_
->Initialize(mock_service_
.get(), mock_frontend_
.get(),
201 const int kHostId
= 1;
202 backend_impl_
->RegisterHost(kHostId
);
203 host_
= backend_impl_
->GetHost(kHostId
);
204 job_factory_
.reset(new MockURLRequestJobFactory());
205 empty_context_
.set_job_factory(job_factory_
.get());
208 void TearDownTest() {
209 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
213 backend_impl_
.reset();
214 mock_frontend_
.reset();
215 mock_service_
.reset();
216 mock_policy_
.reset();
217 job_factory_
.reset();
221 void TestFinished() {
222 // We unwind the stack prior to finishing up to let stack
223 // based objects get deleted.
224 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
225 base::MessageLoop::current()->PostTask(
227 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound
,
228 base::Unretained(this)));
231 void TestFinishedUnwound() {
233 test_finished_event_
->Signal();
236 void PushNextTask(const base::Closure
& task
) {
237 task_stack_
.push(task
);
240 void ScheduleNextTask() {
241 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
242 if (task_stack_
.empty()) {
246 base::MessageLoop::current()->PostTask(FROM_HERE
, task_stack_
.top());
250 // MainResource_Miss --------------------------------------------------
252 void MainResource_Miss() {
254 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss
,
255 base::Unretained(this)));
257 request_
= empty_context_
.CreateRequest(
258 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
259 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
260 RESOURCE_TYPE_MAIN_FRAME
));
261 EXPECT_TRUE(handler_
.get());
263 job_
= handler_
->MaybeLoadResource(request_
.get(),
264 request_
->context()->network_delegate());
265 EXPECT_TRUE(job_
.get());
266 EXPECT_TRUE(job_
->is_waiting());
268 // We have to wait for completion of storage->FindResponseForMainRequest.
272 void Verify_MainResource_Miss() {
273 EXPECT_FALSE(job_
->is_waiting());
274 EXPECT_TRUE(job_
->is_delivering_network_response());
276 int64 cache_id
= kAppCacheNoCacheId
;
278 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
279 EXPECT_EQ(kAppCacheNoCacheId
, cache_id
);
280 EXPECT_EQ(GURL(), manifest_url
);
281 EXPECT_EQ(0, handler_
->found_group_id_
);
283 AppCacheURLRequestJob
* fallback_job
;
284 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
286 request_
->context()->network_delegate(),
287 GURL("http://blah/redirect"));
288 EXPECT_FALSE(fallback_job
);
289 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
290 request_
.get(), request_
->context()->network_delegate());
291 EXPECT_FALSE(fallback_job
);
293 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
298 // MainResource_Hit --------------------------------------------------
300 void MainResource_Hit() {
302 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit
,
303 base::Unretained(this)));
305 request_
= empty_context_
.CreateRequest(
306 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
307 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
308 RESOURCE_TYPE_MAIN_FRAME
));
309 EXPECT_TRUE(handler_
.get());
311 mock_storage()->SimulateFindMainResource(
312 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
313 GURL(), AppCacheEntry(),
314 1, 2, GURL("http://blah/manifest/"));
316 job_
= handler_
->MaybeLoadResource(request_
.get(),
317 request_
->context()->network_delegate());
318 EXPECT_TRUE(job_
.get());
319 EXPECT_TRUE(job_
->is_waiting());
321 // We have to wait for completion of storage->FindResponseForMainRequest.
325 void Verify_MainResource_Hit() {
326 EXPECT_FALSE(job_
->is_waiting());
327 EXPECT_TRUE(job_
->is_delivering_appcache_response());
329 int64 cache_id
= kAppCacheNoCacheId
;
331 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
332 EXPECT_EQ(1, cache_id
);
333 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
334 EXPECT_EQ(2, handler_
->found_group_id_
);
336 AppCacheURLRequestJob
* fallback_job
;
337 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
338 request_
.get(), request_
->context()->network_delegate());
339 EXPECT_FALSE(fallback_job
);
341 EXPECT_EQ(GURL("http://blah/manifest/"),
342 host_
->preferred_manifest_url());
347 // MainResource_Fallback --------------------------------------------------
349 void MainResource_Fallback() {
351 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback
,
352 base::Unretained(this)));
354 request_
= empty_context_
.CreateRequest(
355 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
356 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
357 RESOURCE_TYPE_MAIN_FRAME
));
358 EXPECT_TRUE(handler_
.get());
360 mock_storage()->SimulateFindMainResource(
362 GURL("http://blah/fallbackurl"),
363 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
364 1, 2, GURL("http://blah/manifest/"));
366 job_
= handler_
->MaybeLoadResource(request_
.get(),
367 request_
->context()->network_delegate());
368 EXPECT_TRUE(job_
.get());
369 EXPECT_TRUE(job_
->is_waiting());
371 // We have to wait for completion of storage->FindResponseForMainRequest.
375 void SimulateResponseCode(int response_code
) {
376 job_factory_
->SetJob(
377 new MockURLRequestJob(
379 request_
->context()->network_delegate(),
382 // All our simulation needs to satisfy are the following two DCHECKs
383 DCHECK(request_
->status().is_success());
384 DCHECK_EQ(response_code
, request_
->GetResponseCode());
387 void SimulateResponseInfo(const net::HttpResponseInfo
& info
) {
388 job_factory_
->SetJob(
389 new MockURLRequestJob(
391 request_
->context()->network_delegate(), info
));
395 void Verify_MainResource_Fallback() {
396 EXPECT_FALSE(job_
->is_waiting());
397 EXPECT_TRUE(job_
->is_delivering_network_response());
399 // When the request is restarted, the existing job is dropped so a
400 // real network job gets created. We expect NULL here which will cause
401 // the net library to create a real job.
402 job_
= handler_
->MaybeLoadResource(request_
.get(),
403 request_
->context()->network_delegate());
404 EXPECT_FALSE(job_
.get());
406 // Simulate an http error of the real network job.
407 SimulateResponseCode(500);
409 job_
= handler_
->MaybeLoadFallbackForResponse(
410 request_
.get(), request_
->context()->network_delegate());
411 EXPECT_TRUE(job_
.get());
412 EXPECT_TRUE(job_
->is_delivering_appcache_response());
414 int64 cache_id
= kAppCacheNoCacheId
;
416 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
417 EXPECT_EQ(1, cache_id
);
418 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
419 EXPECT_TRUE(host_
->main_resource_was_namespace_entry_
);
420 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_
->namespace_entry_url_
);
422 EXPECT_EQ(GURL("http://blah/manifest/"),
423 host_
->preferred_manifest_url());
428 // MainResource_FallbackOverride --------------------------------------------
430 void MainResource_FallbackOverride() {
431 PushNextTask(base::Bind(
432 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride
,
433 base::Unretained(this)));
435 request_
= empty_context_
.CreateRequest(
436 GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY
,
438 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
439 RESOURCE_TYPE_MAIN_FRAME
));
440 EXPECT_TRUE(handler_
.get());
442 mock_storage()->SimulateFindMainResource(
444 GURL("http://blah/fallbackurl"),
445 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
446 1, 2, GURL("http://blah/manifest/"));
448 job_
= handler_
->MaybeLoadResource(request_
.get(),
449 request_
->context()->network_delegate());
450 EXPECT_TRUE(job_
.get());
451 EXPECT_TRUE(job_
->is_waiting());
453 // We have to wait for completion of storage->FindResponseForMainRequest.
457 void Verify_MainResource_FallbackOverride() {
458 EXPECT_FALSE(job_
->is_waiting());
459 EXPECT_TRUE(job_
->is_delivering_network_response());
461 // When the request is restarted, the existing job is dropped so a
462 // real network job gets created. We expect NULL here which will cause
463 // the net library to create a real job.
464 job_
= handler_
->MaybeLoadResource(request_
.get(),
465 request_
->context()->network_delegate());
466 EXPECT_FALSE(job_
.get());
468 // Simulate an http error of the real network job, but with custom
469 // headers that override the fallback behavior.
470 const char kOverrideHeaders
[] =
471 "HTTP/1.1 404 BOO HOO\0"
472 "x-chromium-appcache-fallback-override: disallow-fallback\0"
474 net::HttpResponseInfo info
;
475 info
.headers
= new net::HttpResponseHeaders(
476 std::string(kOverrideHeaders
, arraysize(kOverrideHeaders
)));
477 SimulateResponseInfo(info
);
479 job_
= handler_
->MaybeLoadFallbackForResponse(
480 request_
.get(), request_
->context()->network_delegate());
481 EXPECT_FALSE(job_
.get());
486 // SubResource_Miss_WithNoCacheSelected ----------------------------------
488 void SubResource_Miss_WithNoCacheSelected() {
489 request_
= empty_context_
.CreateRequest(
490 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
491 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
492 RESOURCE_TYPE_SUB_RESOURCE
));
494 // We avoid creating handler when possible, sub-resource requests are not
495 // subject to retrieval from an appcache when there's no associated cache.
496 EXPECT_FALSE(handler_
.get());
501 // SubResource_Miss_WithCacheSelected ----------------------------------
503 void SubResource_Miss_WithCacheSelected() {
504 // A sub-resource load where the resource is not in an appcache, or
505 // in a network or fallback namespace, should result in a failed request.
506 host_
->AssociateCompleteCache(MakeNewCache());
508 request_
= empty_context_
.CreateRequest(
509 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
510 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
511 RESOURCE_TYPE_SUB_RESOURCE
));
512 EXPECT_TRUE(handler_
.get());
514 job_
= handler_
->MaybeLoadResource(request_
.get(),
515 request_
->context()->network_delegate());
516 EXPECT_TRUE(job_
.get());
517 EXPECT_TRUE(job_
->is_delivering_error_response());
519 AppCacheURLRequestJob
* fallback_job
;
520 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
522 request_
->context()->network_delegate(),
523 GURL("http://blah/redirect"));
524 EXPECT_FALSE(fallback_job
);
525 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
526 request_
.get(), request_
->context()->network_delegate());
527 EXPECT_FALSE(fallback_job
);
532 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
534 void SubResource_Miss_WithWaitForCacheSelection() {
535 // Precondition, the host is waiting on cache selection.
536 scoped_refptr
<AppCache
> cache(MakeNewCache());
537 host_
->pending_selected_cache_id_
= cache
->cache_id();
538 host_
->set_preferred_manifest_url(cache
->owning_group()->manifest_url());
540 request_
= empty_context_
.CreateRequest(
541 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
542 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
543 RESOURCE_TYPE_SUB_RESOURCE
));
544 EXPECT_TRUE(handler_
.get());
545 job_
= handler_
->MaybeLoadResource(request_
.get(),
546 request_
->context()->network_delegate());
547 EXPECT_TRUE(job_
.get());
548 EXPECT_TRUE(job_
->is_waiting());
550 host_
->FinishCacheSelection(cache
.get(), NULL
);
551 EXPECT_FALSE(job_
->is_waiting());
552 EXPECT_TRUE(job_
->is_delivering_error_response());
554 AppCacheURLRequestJob
* fallback_job
;
555 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
557 request_
->context()->network_delegate(),
558 GURL("http://blah/redirect"));
559 EXPECT_FALSE(fallback_job
);
560 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
561 request_
.get(), request_
->context()->network_delegate());
562 EXPECT_FALSE(fallback_job
);
567 // SubResource_Hit -----------------------------
569 void SubResource_Hit() {
570 host_
->AssociateCompleteCache(MakeNewCache());
572 mock_storage()->SimulateFindSubResource(
573 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
575 request_
= empty_context_
.CreateRequest(
576 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
577 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
578 RESOURCE_TYPE_SUB_RESOURCE
));
579 EXPECT_TRUE(handler_
.get());
580 job_
= handler_
->MaybeLoadResource(request_
.get(),
581 request_
->context()->network_delegate());
582 EXPECT_TRUE(job_
.get());
583 EXPECT_TRUE(job_
->is_delivering_appcache_response());
585 AppCacheURLRequestJob
* fallback_job
;
586 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
588 request_
->context()->network_delegate(),
589 GURL("http://blah/redirect"));
590 EXPECT_FALSE(fallback_job
);
591 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
592 request_
.get(), request_
->context()->network_delegate());
593 EXPECT_FALSE(fallback_job
);
598 // SubResource_RedirectFallback -----------------------------
600 void SubResource_RedirectFallback() {
601 // Redirects to resources in the a different origin are subject to
602 // fallback namespaces.
603 host_
->AssociateCompleteCache(MakeNewCache());
605 mock_storage()->SimulateFindSubResource(
606 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
608 request_
= empty_context_
.CreateRequest(
609 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
610 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
611 RESOURCE_TYPE_SUB_RESOURCE
));
612 EXPECT_TRUE(handler_
.get());
613 job_
= handler_
->MaybeLoadResource(request_
.get(),
614 request_
->context()->network_delegate());
615 EXPECT_FALSE(job_
.get());
617 job_
= handler_
->MaybeLoadFallbackForRedirect(
619 request_
->context()->network_delegate(),
620 GURL("http://not_blah/redirect"));
621 EXPECT_TRUE(job_
.get());
622 EXPECT_TRUE(job_
->is_delivering_appcache_response());
624 AppCacheURLRequestJob
* fallback_job
;
625 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
626 request_
.get(), request_
->context()->network_delegate());
627 EXPECT_FALSE(fallback_job
);
632 // SubResource_NoRedirectFallback -----------------------------
634 void SubResource_NoRedirectFallback() {
635 // Redirects to resources in the same-origin are not subject to
636 // fallback namespaces.
637 host_
->AssociateCompleteCache(MakeNewCache());
639 mock_storage()->SimulateFindSubResource(
640 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
642 request_
= empty_context_
.CreateRequest(
643 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
644 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
645 RESOURCE_TYPE_SUB_RESOURCE
));
646 EXPECT_TRUE(handler_
.get());
647 job_
= handler_
->MaybeLoadResource(request_
.get(),
648 request_
->context()->network_delegate());
649 EXPECT_FALSE(job_
.get());
651 AppCacheURLRequestJob
* fallback_job
;
652 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
654 request_
->context()->network_delegate(),
655 GURL("http://blah/redirect"));
656 EXPECT_FALSE(fallback_job
);
658 SimulateResponseCode(200);
659 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
660 request_
.get(), request_
->context()->network_delegate());
661 EXPECT_FALSE(fallback_job
);
666 // SubResource_Network -----------------------------
668 void SubResource_Network() {
669 // A sub-resource load where the resource is in a network namespace,
670 // should result in the system using a 'real' job to do the network
672 host_
->AssociateCompleteCache(MakeNewCache());
674 mock_storage()->SimulateFindSubResource(
675 AppCacheEntry(), AppCacheEntry(), true);
677 request_
= empty_context_
.CreateRequest(
678 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
679 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
680 RESOURCE_TYPE_SUB_RESOURCE
));
681 EXPECT_TRUE(handler_
.get());
682 job_
= handler_
->MaybeLoadResource(request_
.get(),
683 request_
->context()->network_delegate());
684 EXPECT_FALSE(job_
.get());
686 AppCacheURLRequestJob
* fallback_job
;
687 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
689 request_
->context()->network_delegate(),
690 GURL("http://blah/redirect"));
691 EXPECT_FALSE(fallback_job
);
692 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
693 request_
.get(), request_
->context()->network_delegate());
694 EXPECT_FALSE(fallback_job
);
699 // DestroyedHost -----------------------------
701 void DestroyedHost() {
702 host_
->AssociateCompleteCache(MakeNewCache());
704 mock_storage()->SimulateFindSubResource(
705 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
707 request_
= empty_context_
.CreateRequest(
708 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
709 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
710 RESOURCE_TYPE_SUB_RESOURCE
));
711 EXPECT_TRUE(handler_
.get());
713 backend_impl_
->UnregisterHost(1);
716 EXPECT_FALSE(handler_
->MaybeLoadResource(
717 request_
.get(), request_
->context()->network_delegate()));
718 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
720 request_
->context()->network_delegate(),
721 GURL("http://blah/redirect")));
722 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
723 request_
.get(), request_
->context()->network_delegate()));
728 // DestroyedHostWithWaitingJob -----------------------------
730 void DestroyedHostWithWaitingJob() {
731 // Precondition, the host is waiting on cache selection.
732 host_
->pending_selected_cache_id_
= 1;
734 request_
= empty_context_
.CreateRequest(
735 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
736 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
737 RESOURCE_TYPE_SUB_RESOURCE
));
738 EXPECT_TRUE(handler_
.get());
740 job_
= handler_
->MaybeLoadResource(request_
.get(),
741 request_
->context()->network_delegate());
742 EXPECT_TRUE(job_
.get());
743 EXPECT_TRUE(job_
->is_waiting());
745 backend_impl_
->UnregisterHost(1);
747 EXPECT_TRUE(job_
->has_been_killed());
749 EXPECT_FALSE(handler_
->MaybeLoadResource(
750 request_
.get(), request_
->context()->network_delegate()));
751 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
753 request_
->context()->network_delegate(),
754 GURL("http://blah/redirect")));
755 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
756 request_
.get(), request_
->context()->network_delegate()));
761 // UnsupportedScheme -----------------------------
763 void UnsupportedScheme() {
764 // Precondition, the host is waiting on cache selection.
765 host_
->pending_selected_cache_id_
= 1;
767 request_
= empty_context_
.CreateRequest(
768 GURL("ftp://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
769 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
770 RESOURCE_TYPE_SUB_RESOURCE
));
771 EXPECT_TRUE(handler_
.get()); // we could redirect to http (conceivably)
773 EXPECT_FALSE(handler_
->MaybeLoadResource(
774 request_
.get(), request_
->context()->network_delegate()));
775 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
777 request_
->context()->network_delegate(),
778 GURL("ftp://blah/redirect")));
779 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
780 request_
.get(), request_
->context()->network_delegate()));
785 // CanceledRequest -----------------------------
787 void CanceledRequest() {
788 request_
= empty_context_
.CreateRequest(
789 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
790 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
791 RESOURCE_TYPE_MAIN_FRAME
));
792 EXPECT_TRUE(handler_
.get());
794 job_
= handler_
->MaybeLoadResource(request_
.get(),
795 request_
->context()->network_delegate());
796 EXPECT_TRUE(job_
.get());
797 EXPECT_TRUE(job_
->is_waiting());
798 EXPECT_FALSE(job_
->has_been_started());
800 job_factory_
->SetJob(job_
.get());
802 EXPECT_TRUE(job_
->has_been_started());
805 EXPECT_TRUE(job_
->has_been_killed());
807 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
808 request_
.get(), request_
->context()->network_delegate()));
813 // WorkerRequest -----------------------------
815 void WorkerRequest() {
816 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
817 RESOURCE_TYPE_MAIN_FRAME
));
818 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
819 RESOURCE_TYPE_SUB_FRAME
));
820 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
821 RESOURCE_TYPE_SHARED_WORKER
));
822 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
823 RESOURCE_TYPE_WORKER
));
825 request_
= empty_context_
.CreateRequest(
826 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
828 const int kParentHostId
= host_
->host_id();
829 const int kWorkerHostId
= 2;
830 const int kAbandonedWorkerHostId
= 3;
831 const int kNonExsitingHostId
= 700;
833 backend_impl_
->RegisterHost(kWorkerHostId
);
834 AppCacheHost
* worker_host
= backend_impl_
->GetHost(kWorkerHostId
);
835 worker_host
->SelectCacheForWorker(kParentHostId
, kMockProcessId
);
836 handler_
.reset(worker_host
->CreateRequestHandler(
837 request_
.get(), RESOURCE_TYPE_SHARED_WORKER
));
838 EXPECT_TRUE(handler_
.get());
839 // Verify that the handler is associated with the parent host.
840 EXPECT_EQ(host_
, handler_
->host_
);
842 // Create a new worker host, but associate it with a parent host that
843 // does not exists to simulate the host having been torn down.
844 backend_impl_
->UnregisterHost(kWorkerHostId
);
845 backend_impl_
->RegisterHost(kAbandonedWorkerHostId
);
846 worker_host
= backend_impl_
->GetHost(kAbandonedWorkerHostId
);
847 EXPECT_EQ(NULL
, backend_impl_
->GetHost(kNonExsitingHostId
));
848 worker_host
->SelectCacheForWorker(kNonExsitingHostId
, kMockProcessId
);
849 handler_
.reset(worker_host
->CreateRequestHandler(
850 request_
.get(), RESOURCE_TYPE_SHARED_WORKER
));
851 EXPECT_FALSE(handler_
.get());
856 // MainResource_Blocked --------------------------------------------------
858 void MainResource_Blocked() {
860 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked
,
861 base::Unretained(this)));
863 request_
= empty_context_
.CreateRequest(
864 GURL("http://blah/"), net::DEFAULT_PRIORITY
, &delegate_
, NULL
);
865 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
866 RESOURCE_TYPE_MAIN_FRAME
));
867 EXPECT_TRUE(handler_
.get());
869 mock_policy_
->can_load_return_value_
= false;
870 mock_storage()->SimulateFindMainResource(
871 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
872 GURL(), AppCacheEntry(),
873 1, 2, GURL("http://blah/manifest/"));
875 job_
= handler_
->MaybeLoadResource(request_
.get(),
876 request_
->context()->network_delegate());
877 EXPECT_TRUE(job_
.get());
878 EXPECT_TRUE(job_
->is_waiting());
880 // We have to wait for completion of storage->FindResponseForMainRequest.
884 void Verify_MainResource_Blocked() {
885 EXPECT_FALSE(job_
->is_waiting());
886 EXPECT_FALSE(job_
->is_delivering_appcache_response());
888 EXPECT_EQ(0, handler_
->found_cache_id_
);
889 EXPECT_EQ(0, handler_
->found_group_id_
);
890 EXPECT_TRUE(handler_
->found_manifest_url_
.is_empty());
891 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
892 EXPECT_TRUE(host_
->main_resource_blocked_
);
893 EXPECT_TRUE(host_
->blocked_manifest_url_
== GURL("http://blah/manifest/"));
898 // Test case helpers --------------------------------------------------
900 AppCache
* MakeNewCache() {
901 AppCache
* cache
= new AppCache(
902 mock_storage(), mock_storage()->NewCacheId());
903 cache
->set_complete(true);
904 AppCacheGroup
* group
= new AppCacheGroup(
905 mock_storage(), GURL("http://blah/manifest"),
906 mock_storage()->NewGroupId());
907 group
->AddCache(cache
);
911 MockAppCacheStorage
* mock_storage() {
912 return reinterpret_cast<MockAppCacheStorage
*>(mock_service_
->storage());
915 // Data members --------------------------------------------------
917 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
918 std::stack
<base::Closure
> task_stack_
;
919 scoped_ptr
<MockAppCacheService
> mock_service_
;
920 scoped_ptr
<AppCacheBackendImpl
> backend_impl_
;
921 scoped_ptr
<MockFrontend
> mock_frontend_
;
922 scoped_ptr
<MockAppCachePolicy
> mock_policy_
;
924 net::URLRequestContext empty_context_
;
925 scoped_ptr
<MockURLRequestJobFactory
> job_factory_
;
926 MockURLRequestDelegate delegate_
;
927 scoped_ptr
<net::URLRequest
> request_
;
928 scoped_ptr
<AppCacheRequestHandler
> handler_
;
929 scoped_refptr
<AppCacheURLRequestJob
> job_
;
931 static scoped_ptr
<base::Thread
> io_thread_
;
935 scoped_ptr
<base::Thread
> AppCacheRequestHandlerTest::io_thread_
;
937 TEST_F(AppCacheRequestHandlerTest
, MainResource_Miss
) {
938 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss
);
941 TEST_F(AppCacheRequestHandlerTest
, MainResource_Hit
) {
942 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit
);
945 TEST_F(AppCacheRequestHandlerTest
, MainResource_Fallback
) {
946 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback
);
949 TEST_F(AppCacheRequestHandlerTest
, MainResource_FallbackOverride
) {
951 &AppCacheRequestHandlerTest::MainResource_FallbackOverride
);
954 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithNoCacheSelected
) {
956 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected
);
959 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithCacheSelected
) {
961 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected
);
964 TEST_F(AppCacheRequestHandlerTest
,
965 SubResource_Miss_WithWaitForCacheSelection
) {
967 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection
);
970 TEST_F(AppCacheRequestHandlerTest
, SubResource_Hit
) {
971 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit
);
974 TEST_F(AppCacheRequestHandlerTest
, SubResource_RedirectFallback
) {
975 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback
);
978 TEST_F(AppCacheRequestHandlerTest
, SubResource_NoRedirectFallback
) {
980 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback
);
983 TEST_F(AppCacheRequestHandlerTest
, SubResource_Network
) {
984 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network
);
987 TEST_F(AppCacheRequestHandlerTest
, DestroyedHost
) {
988 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost
);
991 TEST_F(AppCacheRequestHandlerTest
, DestroyedHostWithWaitingJob
) {
992 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob
);
995 TEST_F(AppCacheRequestHandlerTest
, UnsupportedScheme
) {
996 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme
);
999 TEST_F(AppCacheRequestHandlerTest
, CanceledRequest
) {
1000 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest
);
1003 TEST_F(AppCacheRequestHandlerTest
, WorkerRequest
) {
1004 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest
);
1007 TEST_F(AppCacheRequestHandlerTest
, MainResource_Blocked
) {
1008 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked
);
1011 } // namespace content