1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
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 "net/base/net_errors.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_context.h"
19 #include "net/url_request/url_request_error_job.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "webkit/browser/appcache/appcache.h"
22 #include "webkit/browser/appcache/appcache_backend_impl.h"
23 #include "webkit/browser/appcache/appcache_request_handler.h"
24 #include "webkit/browser/appcache/appcache_url_request_job.h"
25 #include "webkit/browser/appcache/mock_appcache_policy.h"
26 #include "webkit/browser/appcache/mock_appcache_service.h"
30 static const int kMockProcessId
= 1;
32 class AppCacheRequestHandlerTest
: public testing::Test
{
34 class MockFrontend
: public AppCacheFrontend
{
36 virtual void OnCacheSelected(
37 int host_id
, const appcache::AppCacheInfo
& info
) OVERRIDE
{}
39 virtual void OnStatusChanged(const std::vector
<int>& host_ids
,
40 appcache::Status status
) OVERRIDE
{}
42 virtual void OnEventRaised(const std::vector
<int>& host_ids
,
43 appcache::EventID event_id
) OVERRIDE
{}
45 virtual void OnErrorEventRaised(const std::vector
<int>& host_ids
,
46 const std::string
& message
) OVERRIDE
{}
48 virtual void OnProgressEventRaised(const std::vector
<int>& host_ids
,
51 int num_complete
) OVERRIDE
{
54 virtual void OnLogMessage(int host_id
,
55 appcache::LogLevel log_level
,
56 const std::string
& message
) OVERRIDE
{
59 virtual void OnContentBlocked(int host_id
,
60 const GURL
& manifest_url
) OVERRIDE
{}
63 // Helper callback to run a test on our io_thread. The io_thread is spun up
64 // once and reused for all tests.
65 template <class Method
>
66 void MethodWrapper(Method method
) {
71 // Subclasses to simulate particular responses so test cases can
72 // exercise fallback code paths.
74 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
75 virtual void OnResponseStarted(net::URLRequest
* request
) OVERRIDE
{}
76 virtual void OnReadCompleted(net::URLRequest
* request
,
77 int bytes_read
) OVERRIDE
{
81 class MockURLRequestJob
: public net::URLRequestJob
{
83 MockURLRequestJob(net::URLRequest
* request
,
84 net::NetworkDelegate
* network_delegate
,
86 : net::URLRequestJob(request
, network_delegate
),
87 response_code_(response_code
),
88 has_response_info_(false) {}
89 MockURLRequestJob(net::URLRequest
* request
,
90 net::NetworkDelegate
* network_delegate
,
91 const net::HttpResponseInfo
& info
)
92 : net::URLRequestJob(request
, network_delegate
),
93 response_code_(info
.headers
->response_code()),
94 has_response_info_(true),
95 response_info_(info
) {}
98 virtual ~MockURLRequestJob() {}
99 virtual void Start() OVERRIDE
{
100 NotifyHeadersComplete();
102 virtual int GetResponseCode() const OVERRIDE
{
103 return response_code_
;
105 virtual void GetResponseInfo(
106 net::HttpResponseInfo
* info
) OVERRIDE
{
107 if (!has_response_info_
)
109 *info
= response_info_
;
114 bool has_response_info_
;
115 net::HttpResponseInfo response_info_
;
118 class MockURLRequest
: public net::URLRequest
{
122 net::URLRequestContext
* context
,
123 net::NetworkDelegate
* network_delegate
) :
124 net::URLRequest(url
, NULL
, context
, network_delegate
),
125 network_delegate_(network_delegate
) {
128 void SimulateResponseCode(int http_response_code
) {
129 mock_factory_job_
= new MockURLRequestJob(
130 this, network_delegate_
, http_response_code
);
132 DCHECK(!mock_factory_job_
);
133 // All our simulation needs to satisfy are the following two DCHECKs
134 DCHECK(status().is_success());
135 DCHECK_EQ(http_response_code
, GetResponseCode());
138 void SimulateResponseInfo(const net::HttpResponseInfo
& info
) {
139 mock_factory_job_
= new MockURLRequestJob(
140 this, network_delegate_
, info
);
141 set_delegate(&delegate_
); // needed to get the info back out
143 DCHECK(!mock_factory_job_
);
146 MockURLRequestDelegate delegate_
;
149 net::NetworkDelegate
* network_delegate_
;
152 static net::URLRequestJob
* MockHttpJobFactory(
153 net::URLRequest
* request
,
154 net::NetworkDelegate
* network_delegate
,
155 const std::string
& scheme
) {
156 if (mock_factory_job_
) {
157 net::URLRequestJob
* temp
= mock_factory_job_
;
158 mock_factory_job_
= NULL
;
161 // Some of these tests trigger UpdateJobs which start URLRequests.
162 // We short circuit those be returning error jobs.
163 return new net::URLRequestErrorJob(request
,
165 net::ERR_INTERNET_DISCONNECTED
);
169 static void SetUpTestCase() {
170 io_thread_
.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
171 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
172 io_thread_
->StartWithOptions(options
);
175 static void TearDownTestCase() {
176 io_thread_
.reset(NULL
);
179 // Test harness --------------------------------------------------
181 AppCacheRequestHandlerTest()
182 : host_(NULL
), empty_network_delegate_(NULL
), orig_http_factory_(NULL
) {
185 template <class Method
>
186 void RunTestOnIOThread(Method method
) {
187 test_finished_event_
.reset(new base::WaitableEvent(false, false));
188 io_thread_
->message_loop()->PostTask(
190 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper
<Method
>,
191 base::Unretained(this), method
));
192 test_finished_event_
->Wait();
196 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
197 orig_http_factory_
= net::URLRequest::Deprecated::RegisterProtocolFactory(
198 "http", MockHttpJobFactory
);
199 mock_service_
.reset(new MockAppCacheService
);
200 mock_service_
->set_request_context(&empty_context_
);
201 mock_policy_
.reset(new MockAppCachePolicy
);
202 mock_service_
->set_appcache_policy(mock_policy_
.get());
203 mock_frontend_
.reset(new MockFrontend
);
204 backend_impl_
.reset(new AppCacheBackendImpl
);
205 backend_impl_
->Initialize(mock_service_
.get(), mock_frontend_
.get(),
207 const int kHostId
= 1;
208 backend_impl_
->RegisterHost(kHostId
);
209 host_
= backend_impl_
->GetHost(kHostId
);
210 empty_network_delegate_
= NULL
;
213 void TearDownTest() {
214 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
215 DCHECK(!mock_factory_job_
);
216 net::URLRequest::Deprecated::RegisterProtocolFactory(
217 "http", orig_http_factory_
);
218 orig_http_factory_
= NULL
;
222 backend_impl_
.reset();
223 mock_frontend_
.reset();
224 mock_service_
.reset();
225 mock_policy_
.reset();
227 empty_network_delegate_
= NULL
;
230 void TestFinished() {
231 // We unwind the stack prior to finishing up to let stack
232 // based objects get deleted.
233 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
234 base::MessageLoop::current()->PostTask(
236 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound
,
237 base::Unretained(this)));
240 void TestFinishedUnwound() {
242 test_finished_event_
->Signal();
245 void PushNextTask(const base::Closure
& task
) {
246 task_stack_
.push(task
);
249 void ScheduleNextTask() {
250 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
251 if (task_stack_
.empty()) {
255 base::MessageLoop::current()->PostTask(FROM_HERE
, task_stack_
.top());
259 // MainResource_Miss --------------------------------------------------
261 void MainResource_Miss() {
263 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss
,
264 base::Unretained(this)));
266 request_
.reset(new MockURLRequest(
267 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
268 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
269 ResourceType::MAIN_FRAME
));
270 EXPECT_TRUE(handler_
.get());
272 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
273 EXPECT_TRUE(job_
.get());
274 EXPECT_TRUE(job_
->is_waiting());
276 // We have to wait for completion of storage->FindResponseForMainRequest.
280 void Verify_MainResource_Miss() {
281 EXPECT_FALSE(job_
->is_waiting());
282 EXPECT_TRUE(job_
->is_delivering_network_response());
284 int64 cache_id
= kNoCacheId
;
286 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
287 EXPECT_EQ(kNoCacheId
, cache_id
);
288 EXPECT_EQ(GURL(), manifest_url
);
289 EXPECT_EQ(0, handler_
->found_group_id_
);
291 AppCacheURLRequestJob
* fallback_job
;
292 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
294 empty_network_delegate_
,
295 GURL("http://blah/redirect"));
296 EXPECT_FALSE(fallback_job
);
297 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
298 request_
.get(), empty_network_delegate_
);
299 EXPECT_FALSE(fallback_job
);
301 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
306 // MainResource_Hit --------------------------------------------------
308 void MainResource_Hit() {
310 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit
,
311 base::Unretained(this)));
313 request_
.reset(new MockURLRequest(
314 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
315 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
316 ResourceType::MAIN_FRAME
));
317 EXPECT_TRUE(handler_
.get());
319 mock_storage()->SimulateFindMainResource(
320 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
321 GURL(), AppCacheEntry(),
322 1, 2, GURL("http://blah/manifest/"));
324 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
325 EXPECT_TRUE(job_
.get());
326 EXPECT_TRUE(job_
->is_waiting());
328 // We have to wait for completion of storage->FindResponseForMainRequest.
332 void Verify_MainResource_Hit() {
333 EXPECT_FALSE(job_
->is_waiting());
334 EXPECT_TRUE(job_
->is_delivering_appcache_response());
336 int64 cache_id
= kNoCacheId
;
338 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
339 EXPECT_EQ(1, cache_id
);
340 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
341 EXPECT_EQ(2, handler_
->found_group_id_
);
343 AppCacheURLRequestJob
* fallback_job
;
344 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
345 request_
.get(), empty_network_delegate_
);
346 EXPECT_FALSE(fallback_job
);
348 EXPECT_EQ(GURL("http://blah/manifest/"),
349 host_
->preferred_manifest_url());
354 // MainResource_Fallback --------------------------------------------------
356 void MainResource_Fallback() {
358 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback
,
359 base::Unretained(this)));
361 request_
.reset(new MockURLRequest(
362 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
363 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
364 ResourceType::MAIN_FRAME
));
365 EXPECT_TRUE(handler_
.get());
367 mock_storage()->SimulateFindMainResource(
369 GURL("http://blah/fallbackurl"),
370 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
371 1, 2, GURL("http://blah/manifest/"));
373 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
374 EXPECT_TRUE(job_
.get());
375 EXPECT_TRUE(job_
->is_waiting());
377 // We have to wait for completion of storage->FindResponseForMainRequest.
381 void Verify_MainResource_Fallback() {
382 EXPECT_FALSE(job_
->is_waiting());
383 EXPECT_TRUE(job_
->is_delivering_network_response());
385 // When the request is restarted, the existing job is dropped so a
386 // real network job gets created. We expect NULL here which will cause
387 // the net library to create a real job.
388 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
389 EXPECT_FALSE(job_
.get());
391 // Simulate an http error of the real network job.
392 request_
->SimulateResponseCode(500);
394 job_
= handler_
->MaybeLoadFallbackForResponse(
395 request_
.get(), empty_network_delegate_
);
396 EXPECT_TRUE(job_
.get());
397 EXPECT_TRUE(job_
->is_delivering_appcache_response());
399 int64 cache_id
= kNoCacheId
;
401 handler_
->GetExtraResponseInfo(&cache_id
, &manifest_url
);
402 EXPECT_EQ(1, cache_id
);
403 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url
);
404 EXPECT_TRUE(host_
->main_resource_was_namespace_entry_
);
405 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_
->namespace_entry_url_
);
407 EXPECT_EQ(GURL("http://blah/manifest/"),
408 host_
->preferred_manifest_url());
413 // MainResource_FallbackOverride --------------------------------------------
415 void MainResource_FallbackOverride() {
416 PushNextTask(base::Bind(
417 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride
,
418 base::Unretained(this)));
420 request_
.reset(new MockURLRequest(
421 GURL("http://blah/fallback-override"),
422 &empty_context_
, empty_network_delegate_
));
423 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
424 ResourceType::MAIN_FRAME
));
425 EXPECT_TRUE(handler_
.get());
427 mock_storage()->SimulateFindMainResource(
429 GURL("http://blah/fallbackurl"),
430 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
431 1, 2, GURL("http://blah/manifest/"));
433 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
434 EXPECT_TRUE(job_
.get());
435 EXPECT_TRUE(job_
->is_waiting());
437 // We have to wait for completion of storage->FindResponseForMainRequest.
441 void Verify_MainResource_FallbackOverride() {
442 EXPECT_FALSE(job_
->is_waiting());
443 EXPECT_TRUE(job_
->is_delivering_network_response());
445 // When the request is restarted, the existing job is dropped so a
446 // real network job gets created. We expect NULL here which will cause
447 // the net library to create a real job.
448 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
449 EXPECT_FALSE(job_
.get());
451 // Simulate an http error of the real network job, but with custom
452 // headers that override the fallback behavior.
453 const char kOverrideHeaders
[] =
454 "HTTP/1.1 404 BOO HOO\0"
455 "x-chromium-appcache-fallback-override: disallow-fallback\0"
457 net::HttpResponseInfo info
;
458 info
.headers
= new net::HttpResponseHeaders(
459 std::string(kOverrideHeaders
, arraysize(kOverrideHeaders
)));
460 request_
->SimulateResponseInfo(info
);
462 job_
= handler_
->MaybeLoadFallbackForResponse(
463 request_
.get(), empty_network_delegate_
);
464 EXPECT_FALSE(job_
.get());
469 // SubResource_Miss_WithNoCacheSelected ----------------------------------
471 void SubResource_Miss_WithNoCacheSelected() {
472 request_
.reset(new MockURLRequest(
473 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
474 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
475 ResourceType::SUB_RESOURCE
));
477 // We avoid creating handler when possible, sub-resource requests are not
478 // subject to retrieval from an appcache when there's no associated cache.
479 EXPECT_FALSE(handler_
.get());
484 // SubResource_Miss_WithCacheSelected ----------------------------------
486 void SubResource_Miss_WithCacheSelected() {
487 // A sub-resource load where the resource is not in an appcache, or
488 // in a network or fallback namespace, should result in a failed request.
489 host_
->AssociateCompleteCache(MakeNewCache());
491 request_
.reset(new MockURLRequest(
492 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
493 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
494 ResourceType::SUB_RESOURCE
));
495 EXPECT_TRUE(handler_
.get());
497 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
498 EXPECT_TRUE(job_
.get());
499 EXPECT_TRUE(job_
->is_delivering_error_response());
501 AppCacheURLRequestJob
* fallback_job
;
502 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
503 request_
.get(), empty_network_delegate_
, GURL("http://blah/redirect"));
504 EXPECT_FALSE(fallback_job
);
505 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
506 request_
.get(), empty_network_delegate_
);
507 EXPECT_FALSE(fallback_job
);
512 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
514 void SubResource_Miss_WithWaitForCacheSelection() {
515 // Precondition, the host is waiting on cache selection.
516 scoped_refptr
<AppCache
> cache(MakeNewCache());
517 host_
->pending_selected_cache_id_
= cache
->cache_id();
518 host_
->set_preferred_manifest_url(cache
->owning_group()->manifest_url());
520 request_
.reset(new MockURLRequest(
521 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
522 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
523 ResourceType::SUB_RESOURCE
));
524 EXPECT_TRUE(handler_
.get());
525 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
526 EXPECT_TRUE(job_
.get());
527 EXPECT_TRUE(job_
->is_waiting());
529 host_
->FinishCacheSelection(cache
.get(), NULL
);
530 EXPECT_FALSE(job_
->is_waiting());
531 EXPECT_TRUE(job_
->is_delivering_error_response());
533 AppCacheURLRequestJob
* fallback_job
;
534 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
535 request_
.get(), empty_network_delegate_
, GURL("http://blah/redirect"));
536 EXPECT_FALSE(fallback_job
);
537 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
538 request_
.get(), empty_network_delegate_
);
539 EXPECT_FALSE(fallback_job
);
544 // SubResource_Hit -----------------------------
546 void SubResource_Hit() {
547 host_
->AssociateCompleteCache(MakeNewCache());
549 mock_storage()->SimulateFindSubResource(
550 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
552 request_
.reset(new MockURLRequest(
553 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
554 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
555 ResourceType::SUB_RESOURCE
));
556 EXPECT_TRUE(handler_
.get());
557 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
558 EXPECT_TRUE(job_
.get());
559 EXPECT_TRUE(job_
->is_delivering_appcache_response());
561 AppCacheURLRequestJob
* fallback_job
;
562 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
563 request_
.get(), empty_network_delegate_
, GURL("http://blah/redirect"));
564 EXPECT_FALSE(fallback_job
);
565 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
566 request_
.get(), empty_network_delegate_
);
567 EXPECT_FALSE(fallback_job
);
572 // SubResource_RedirectFallback -----------------------------
574 void SubResource_RedirectFallback() {
575 // Redirects to resources in the a different origin are subject to
576 // fallback namespaces.
577 host_
->AssociateCompleteCache(MakeNewCache());
579 mock_storage()->SimulateFindSubResource(
580 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
582 request_
.reset(new MockURLRequest(
583 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
584 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
585 ResourceType::SUB_RESOURCE
));
586 EXPECT_TRUE(handler_
.get());
587 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
588 EXPECT_FALSE(job_
.get());
590 job_
= handler_
->MaybeLoadFallbackForRedirect(
592 empty_network_delegate_
,
593 GURL("http://not_blah/redirect"));
594 EXPECT_TRUE(job_
.get());
595 EXPECT_TRUE(job_
->is_delivering_appcache_response());
597 AppCacheURLRequestJob
* fallback_job
;
598 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
599 request_
.get(), empty_network_delegate_
);
600 EXPECT_FALSE(fallback_job
);
605 // SubResource_NoRedirectFallback -----------------------------
607 void SubResource_NoRedirectFallback() {
608 // Redirects to resources in the same-origin are not subject to
609 // fallback namespaces.
610 host_
->AssociateCompleteCache(MakeNewCache());
612 mock_storage()->SimulateFindSubResource(
613 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), false);
615 request_
.reset(new MockURLRequest(
616 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
617 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
618 ResourceType::SUB_RESOURCE
));
619 EXPECT_TRUE(handler_
.get());
620 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
621 EXPECT_FALSE(job_
.get());
623 AppCacheURLRequestJob
* fallback_job
;
624 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
625 request_
.get(), empty_network_delegate_
, GURL("http://blah/redirect"));
626 EXPECT_FALSE(fallback_job
);
628 request_
->SimulateResponseCode(200);
629 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
630 request_
.get(), empty_network_delegate_
);
631 EXPECT_FALSE(fallback_job
);
636 // SubResource_Network -----------------------------
638 void SubResource_Network() {
639 // A sub-resource load where the resource is in a network namespace,
640 // should result in the system using a 'real' job to do the network
642 host_
->AssociateCompleteCache(MakeNewCache());
644 mock_storage()->SimulateFindSubResource(
645 AppCacheEntry(), AppCacheEntry(), true);
647 request_
.reset(new MockURLRequest(
648 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
649 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
650 ResourceType::SUB_RESOURCE
));
651 EXPECT_TRUE(handler_
.get());
652 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
653 EXPECT_FALSE(job_
.get());
655 AppCacheURLRequestJob
* fallback_job
;
656 fallback_job
= handler_
->MaybeLoadFallbackForRedirect(
657 request_
.get(), empty_network_delegate_
, GURL("http://blah/redirect"));
658 EXPECT_FALSE(fallback_job
);
659 fallback_job
= handler_
->MaybeLoadFallbackForResponse(
660 request_
.get(), empty_network_delegate_
);
661 EXPECT_FALSE(fallback_job
);
666 // DestroyedHost -----------------------------
668 void DestroyedHost() {
669 host_
->AssociateCompleteCache(MakeNewCache());
671 mock_storage()->SimulateFindSubResource(
672 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1), AppCacheEntry(), false);
674 request_
.reset(new MockURLRequest(
675 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
676 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
677 ResourceType::SUB_RESOURCE
));
678 EXPECT_TRUE(handler_
.get());
680 backend_impl_
->UnregisterHost(1);
683 EXPECT_FALSE(handler_
->MaybeLoadResource(
684 request_
.get(), empty_network_delegate_
));
685 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
686 request_
.get(), empty_network_delegate_
, GURL("http://blah/redirect")));
687 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
688 request_
.get(), empty_network_delegate_
));
693 // DestroyedHostWithWaitingJob -----------------------------
695 void DestroyedHostWithWaitingJob() {
696 // Precondition, the host is waiting on cache selection.
697 host_
->pending_selected_cache_id_
= 1;
699 request_
.reset(new MockURLRequest(
700 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
701 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
702 ResourceType::SUB_RESOURCE
));
703 EXPECT_TRUE(handler_
.get());
705 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
706 EXPECT_TRUE(job_
.get());
707 EXPECT_TRUE(job_
->is_waiting());
709 backend_impl_
->UnregisterHost(1);
711 EXPECT_TRUE(job_
->has_been_killed());
713 EXPECT_FALSE(handler_
->MaybeLoadResource(
714 request_
.get(), empty_network_delegate_
));
715 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
716 request_
.get(), empty_network_delegate_
, GURL("http://blah/redirect")));
717 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
718 request_
.get(), empty_network_delegate_
));
723 // UnsupportedScheme -----------------------------
725 void UnsupportedScheme() {
726 // Precondition, the host is waiting on cache selection.
727 host_
->pending_selected_cache_id_
= 1;
729 request_
.reset(new MockURLRequest(
730 GURL("ftp://blah/"), &empty_context_
, empty_network_delegate_
));
731 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
732 ResourceType::SUB_RESOURCE
));
733 EXPECT_TRUE(handler_
.get()); // we could redirect to http (conceivably)
735 EXPECT_FALSE(handler_
->MaybeLoadResource(
736 request_
.get(), empty_network_delegate_
));
737 EXPECT_FALSE(handler_
->MaybeLoadFallbackForRedirect(
738 request_
.get(), empty_network_delegate_
, GURL("ftp://blah/redirect")));
739 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
740 request_
.get(), empty_network_delegate_
));
745 // CanceledRequest -----------------------------
747 void CanceledRequest() {
748 request_
.reset(new MockURLRequest(
749 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
750 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
751 ResourceType::MAIN_FRAME
));
752 EXPECT_TRUE(handler_
.get());
754 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
755 EXPECT_TRUE(job_
.get());
756 EXPECT_TRUE(job_
->is_waiting());
757 EXPECT_FALSE(job_
->has_been_started());
759 mock_factory_job_
= job_
.get();
761 EXPECT_TRUE(job_
->has_been_started());
764 EXPECT_TRUE(job_
->has_been_killed());
766 EXPECT_FALSE(handler_
->MaybeLoadFallbackForResponse(
767 request_
.get(), empty_network_delegate_
));
772 // WorkerRequest -----------------------------
774 void WorkerRequest() {
775 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
776 ResourceType::MAIN_FRAME
));
777 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
778 ResourceType::SUB_FRAME
));
779 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
780 ResourceType::SHARED_WORKER
));
781 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
782 ResourceType::WORKER
));
784 request_
.reset(new MockURLRequest(
785 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
787 const int kParentHostId
= host_
->host_id();
788 const int kWorkerHostId
= 2;
789 const int kAbandonedWorkerHostId
= 3;
790 const int kNonExsitingHostId
= 700;
792 backend_impl_
->RegisterHost(kWorkerHostId
);
793 AppCacheHost
* worker_host
= backend_impl_
->GetHost(kWorkerHostId
);
794 worker_host
->SelectCacheForWorker(kParentHostId
, kMockProcessId
);
795 handler_
.reset(worker_host
->CreateRequestHandler(
796 request_
.get(), ResourceType::SHARED_WORKER
));
797 EXPECT_TRUE(handler_
.get());
798 // Verify that the handler is associated with the parent host.
799 EXPECT_EQ(host_
, handler_
->host_
);
801 // Create a new worker host, but associate it with a parent host that
802 // does not exists to simulate the host having been torn down.
803 backend_impl_
->UnregisterHost(kWorkerHostId
);
804 backend_impl_
->RegisterHost(kAbandonedWorkerHostId
);
805 worker_host
= backend_impl_
->GetHost(kAbandonedWorkerHostId
);
806 EXPECT_EQ(NULL
, backend_impl_
->GetHost(kNonExsitingHostId
));
807 worker_host
->SelectCacheForWorker(kNonExsitingHostId
, kMockProcessId
);
808 handler_
.reset(worker_host
->CreateRequestHandler(
809 request_
.get(), ResourceType::SHARED_WORKER
));
810 EXPECT_FALSE(handler_
.get());
815 // MainResource_Blocked --------------------------------------------------
817 void MainResource_Blocked() {
819 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked
,
820 base::Unretained(this)));
822 request_
.reset(new MockURLRequest(
823 GURL("http://blah/"), &empty_context_
, empty_network_delegate_
));
824 handler_
.reset(host_
->CreateRequestHandler(request_
.get(),
825 ResourceType::MAIN_FRAME
));
826 EXPECT_TRUE(handler_
.get());
828 mock_policy_
->can_load_return_value_
= false;
829 mock_storage()->SimulateFindMainResource(
830 AppCacheEntry(AppCacheEntry::EXPLICIT
, 1),
831 GURL(), AppCacheEntry(),
832 1, 2, GURL("http://blah/manifest/"));
834 job_
= handler_
->MaybeLoadResource(request_
.get(), empty_network_delegate_
);
835 EXPECT_TRUE(job_
.get());
836 EXPECT_TRUE(job_
->is_waiting());
838 // We have to wait for completion of storage->FindResponseForMainRequest.
842 void Verify_MainResource_Blocked() {
843 EXPECT_FALSE(job_
->is_waiting());
844 EXPECT_FALSE(job_
->is_delivering_appcache_response());
846 EXPECT_EQ(0, handler_
->found_cache_id_
);
847 EXPECT_EQ(0, handler_
->found_group_id_
);
848 EXPECT_TRUE(handler_
->found_manifest_url_
.is_empty());
849 EXPECT_TRUE(host_
->preferred_manifest_url().is_empty());
850 EXPECT_TRUE(host_
->main_resource_blocked_
);
851 EXPECT_TRUE(host_
->blocked_manifest_url_
== GURL("http://blah/manifest/"));
856 // Test case helpers --------------------------------------------------
858 AppCache
* MakeNewCache() {
859 AppCache
* cache
= new AppCache(
860 mock_storage(), mock_storage()->NewCacheId());
861 cache
->set_complete(true);
862 AppCacheGroup
* group
= new AppCacheGroup(
863 mock_storage(), GURL("http://blah/manifest"),
864 mock_storage()->NewGroupId());
865 group
->AddCache(cache
);
869 MockAppCacheStorage
* mock_storage() {
870 return reinterpret_cast<MockAppCacheStorage
*>(mock_service_
->storage());
873 // Data members --------------------------------------------------
875 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
876 std::stack
<base::Closure
> task_stack_
;
877 scoped_ptr
<MockAppCacheService
> mock_service_
;
878 scoped_ptr
<AppCacheBackendImpl
> backend_impl_
;
879 scoped_ptr
<MockFrontend
> mock_frontend_
;
880 scoped_ptr
<MockAppCachePolicy
> mock_policy_
;
882 net::URLRequestContext empty_context_
;
883 net::NetworkDelegate
* empty_network_delegate_
;
884 scoped_ptr
<MockURLRequest
> request_
;
885 scoped_ptr
<AppCacheRequestHandler
> handler_
;
886 scoped_refptr
<AppCacheURLRequestJob
> job_
;
887 net::URLRequest::ProtocolFactory
* orig_http_factory_
;
889 static scoped_ptr
<base::Thread
> io_thread_
;
890 static net::URLRequestJob
* mock_factory_job_
;
894 scoped_ptr
<base::Thread
> AppCacheRequestHandlerTest::io_thread_
;
895 net::URLRequestJob
* AppCacheRequestHandlerTest::mock_factory_job_
= NULL
;
897 TEST_F(AppCacheRequestHandlerTest
, MainResource_Miss
) {
898 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss
);
901 TEST_F(AppCacheRequestHandlerTest
, MainResource_Hit
) {
902 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit
);
905 TEST_F(AppCacheRequestHandlerTest
, MainResource_Fallback
) {
906 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback
);
909 TEST_F(AppCacheRequestHandlerTest
, MainResource_FallbackOverride
) {
911 &AppCacheRequestHandlerTest::MainResource_FallbackOverride
);
914 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithNoCacheSelected
) {
916 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected
);
919 TEST_F(AppCacheRequestHandlerTest
, SubResource_Miss_WithCacheSelected
) {
921 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected
);
924 TEST_F(AppCacheRequestHandlerTest
,
925 SubResource_Miss_WithWaitForCacheSelection
) {
927 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection
);
930 TEST_F(AppCacheRequestHandlerTest
, SubResource_Hit
) {
931 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit
);
934 TEST_F(AppCacheRequestHandlerTest
, SubResource_RedirectFallback
) {
935 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback
);
938 TEST_F(AppCacheRequestHandlerTest
, SubResource_NoRedirectFallback
) {
940 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback
);
943 TEST_F(AppCacheRequestHandlerTest
, SubResource_Network
) {
944 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network
);
947 TEST_F(AppCacheRequestHandlerTest
, DestroyedHost
) {
948 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost
);
951 TEST_F(AppCacheRequestHandlerTest
, DestroyedHostWithWaitingJob
) {
952 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob
);
955 TEST_F(AppCacheRequestHandlerTest
, UnsupportedScheme
) {
956 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme
);
959 TEST_F(AppCacheRequestHandlerTest
, CanceledRequest
) {
960 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest
);
963 TEST_F(AppCacheRequestHandlerTest
, WorkerRequest
) {
964 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest
);
967 TEST_F(AppCacheRequestHandlerTest
, MainResource_Blocked
) {
968 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked
);
971 } // namespace appcache