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/base/request_priority.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_context.h"
20 #include "net/url_request/url_request_error_job.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "webkit/browser/appcache/appcache.h"
23 #include "webkit/browser/appcache/appcache_backend_impl.h"
24 #include "webkit/browser/appcache/appcache_request_handler.h"
25 #include "webkit/browser/appcache/appcache_url_request_job.h"
26 #include "webkit/browser/appcache/mock_appcache_policy.h"
27 #include "webkit/browser/appcache/mock_appcache_service.h"
31 static const int kMockProcessId = 1;
33 class AppCacheRequestHandlerTest : public testing::Test {
35 class MockFrontend : public AppCacheFrontend {
37 virtual void OnCacheSelected(
38 int host_id, const appcache::AppCacheInfo& info) OVERRIDE {}
40 virtual void OnStatusChanged(const std::vector<int>& host_ids,
41 appcache::Status status) OVERRIDE {}
43 virtual void OnEventRaised(const std::vector<int>& host_ids,
44 appcache::EventID event_id) OVERRIDE {}
46 virtual void OnErrorEventRaised(const std::vector<int>& host_ids,
47 const std::string& message) OVERRIDE {}
49 virtual void OnProgressEventRaised(const std::vector<int>& host_ids,
52 int num_complete) OVERRIDE {
55 virtual void OnLogMessage(int host_id,
56 appcache::LogLevel log_level,
57 const std::string& message) OVERRIDE {
60 virtual void OnContentBlocked(int host_id,
61 const GURL& manifest_url) OVERRIDE {}
64 // Helper callback to run a test on our io_thread. The io_thread is spun up
65 // once and reused for all tests.
66 template <class Method>
67 void MethodWrapper(Method method) {
72 // Subclasses to simulate particular responses so test cases can
73 // exercise fallback code paths.
75 class MockURLRequestDelegate : public net::URLRequest::Delegate {
76 virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {}
77 virtual void OnReadCompleted(net::URLRequest* request,
78 int bytes_read) OVERRIDE {
82 class MockURLRequestJob : public net::URLRequestJob {
84 MockURLRequestJob(net::URLRequest* request,
85 net::NetworkDelegate* network_delegate,
87 : net::URLRequestJob(request, network_delegate),
88 response_code_(response_code),
89 has_response_info_(false) {}
90 MockURLRequestJob(net::URLRequest* request,
91 net::NetworkDelegate* network_delegate,
92 const net::HttpResponseInfo& info)
93 : net::URLRequestJob(request, network_delegate),
94 response_code_(info.headers->response_code()),
95 has_response_info_(true),
96 response_info_(info) {}
99 virtual ~MockURLRequestJob() {}
100 virtual void Start() OVERRIDE {
101 NotifyHeadersComplete();
103 virtual int GetResponseCode() const OVERRIDE {
104 return response_code_;
106 virtual void GetResponseInfo(
107 net::HttpResponseInfo* info) OVERRIDE {
108 if (!has_response_info_)
110 *info = response_info_;
115 bool has_response_info_;
116 net::HttpResponseInfo response_info_;
119 class MockURLRequest : public net::URLRequest {
121 MockURLRequest(const GURL& url, net::URLRequestContext* context)
122 : net::URLRequest(url, net::DEFAULT_PRIORITY, NULL, context) {}
124 void SimulateResponseCode(int http_response_code) {
125 mock_factory_job_ = new MockURLRequestJob(
126 this, context()->network_delegate(), http_response_code);
128 DCHECK(!mock_factory_job_);
129 // All our simulation needs to satisfy are the following two DCHECKs
130 DCHECK(status().is_success());
131 DCHECK_EQ(http_response_code, GetResponseCode());
134 void SimulateResponseInfo(const net::HttpResponseInfo& info) {
136 new MockURLRequestJob(this, context()->network_delegate(), info);
137 set_delegate(&delegate_); // needed to get the info back out
139 DCHECK(!mock_factory_job_);
142 MockURLRequestDelegate delegate_;
145 static net::URLRequestJob* MockHttpJobFactory(
146 net::URLRequest* request,
147 net::NetworkDelegate* network_delegate,
148 const std::string& scheme) {
149 if (mock_factory_job_) {
150 net::URLRequestJob* temp = mock_factory_job_;
151 mock_factory_job_ = NULL;
154 // Some of these tests trigger UpdateJobs which start URLRequests.
155 // We short circuit those be returning error jobs.
156 return new net::URLRequestErrorJob(request,
158 net::ERR_INTERNET_DISCONNECTED);
162 static void SetUpTestCase() {
163 io_thread_.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
164 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
165 io_thread_->StartWithOptions(options);
168 static void TearDownTestCase() {
169 io_thread_.reset(NULL);
172 // Test harness --------------------------------------------------
174 AppCacheRequestHandlerTest() : host_(NULL), orig_http_factory_(NULL) {}
176 template <class Method>
177 void RunTestOnIOThread(Method method) {
178 test_finished_event_ .reset(new base::WaitableEvent(false, false));
179 io_thread_->message_loop()->PostTask(
181 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper<Method>,
182 base::Unretained(this), method));
183 test_finished_event_->Wait();
187 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
188 orig_http_factory_ = net::URLRequest::Deprecated::RegisterProtocolFactory(
189 "http", MockHttpJobFactory);
190 mock_service_.reset(new MockAppCacheService);
191 mock_service_->set_request_context(&empty_context_);
192 mock_policy_.reset(new MockAppCachePolicy);
193 mock_service_->set_appcache_policy(mock_policy_.get());
194 mock_frontend_.reset(new MockFrontend);
195 backend_impl_.reset(new AppCacheBackendImpl);
196 backend_impl_->Initialize(mock_service_.get(), mock_frontend_.get(),
198 const int kHostId = 1;
199 backend_impl_->RegisterHost(kHostId);
200 host_ = backend_impl_->GetHost(kHostId);
203 void TearDownTest() {
204 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
205 DCHECK(!mock_factory_job_);
206 net::URLRequest::Deprecated::RegisterProtocolFactory(
207 "http", orig_http_factory_);
208 orig_http_factory_ = NULL;
212 backend_impl_.reset();
213 mock_frontend_.reset();
214 mock_service_.reset();
215 mock_policy_.reset();
219 void TestFinished() {
220 // We unwind the stack prior to finishing up to let stack
221 // based objects get deleted.
222 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
223 base::MessageLoop::current()->PostTask(
225 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound,
226 base::Unretained(this)));
229 void TestFinishedUnwound() {
231 test_finished_event_->Signal();
234 void PushNextTask(const base::Closure& task) {
235 task_stack_.push(task);
238 void ScheduleNextTask() {
239 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
240 if (task_stack_.empty()) {
244 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
248 // MainResource_Miss --------------------------------------------------
250 void MainResource_Miss() {
252 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss,
253 base::Unretained(this)));
255 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
256 handler_.reset(host_->CreateRequestHandler(request_.get(),
257 ResourceType::MAIN_FRAME));
258 EXPECT_TRUE(handler_.get());
260 job_ = handler_->MaybeLoadResource(request_.get(),
261 request_->context()->network_delegate());
262 EXPECT_TRUE(job_.get());
263 EXPECT_TRUE(job_->is_waiting());
265 // We have to wait for completion of storage->FindResponseForMainRequest.
269 void Verify_MainResource_Miss() {
270 EXPECT_FALSE(job_->is_waiting());
271 EXPECT_TRUE(job_->is_delivering_network_response());
273 int64 cache_id = kNoCacheId;
275 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
276 EXPECT_EQ(kNoCacheId, cache_id);
277 EXPECT_EQ(GURL(), manifest_url);
278 EXPECT_EQ(0, handler_->found_group_id_);
280 AppCacheURLRequestJob* fallback_job;
281 fallback_job = handler_->MaybeLoadFallbackForRedirect(
283 request_->context()->network_delegate(),
284 GURL("http://blah/redirect"));
285 EXPECT_FALSE(fallback_job);
286 fallback_job = handler_->MaybeLoadFallbackForResponse(
287 request_.get(), request_->context()->network_delegate());
288 EXPECT_FALSE(fallback_job);
290 EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
295 // MainResource_Hit --------------------------------------------------
297 void MainResource_Hit() {
299 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit,
300 base::Unretained(this)));
302 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
303 handler_.reset(host_->CreateRequestHandler(request_.get(),
304 ResourceType::MAIN_FRAME));
305 EXPECT_TRUE(handler_.get());
307 mock_storage()->SimulateFindMainResource(
308 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
309 GURL(), AppCacheEntry(),
310 1, 2, GURL("http://blah/manifest/"));
312 job_ = handler_->MaybeLoadResource(request_.get(),
313 request_->context()->network_delegate());
314 EXPECT_TRUE(job_.get());
315 EXPECT_TRUE(job_->is_waiting());
317 // We have to wait for completion of storage->FindResponseForMainRequest.
321 void Verify_MainResource_Hit() {
322 EXPECT_FALSE(job_->is_waiting());
323 EXPECT_TRUE(job_->is_delivering_appcache_response());
325 int64 cache_id = kNoCacheId;
327 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
328 EXPECT_EQ(1, cache_id);
329 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
330 EXPECT_EQ(2, handler_->found_group_id_);
332 AppCacheURLRequestJob* fallback_job;
333 fallback_job = handler_->MaybeLoadFallbackForResponse(
334 request_.get(), request_->context()->network_delegate());
335 EXPECT_FALSE(fallback_job);
337 EXPECT_EQ(GURL("http://blah/manifest/"),
338 host_->preferred_manifest_url());
343 // MainResource_Fallback --------------------------------------------------
345 void MainResource_Fallback() {
347 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback,
348 base::Unretained(this)));
350 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
351 handler_.reset(host_->CreateRequestHandler(request_.get(),
352 ResourceType::MAIN_FRAME));
353 EXPECT_TRUE(handler_.get());
355 mock_storage()->SimulateFindMainResource(
357 GURL("http://blah/fallbackurl"),
358 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
359 1, 2, GURL("http://blah/manifest/"));
361 job_ = handler_->MaybeLoadResource(request_.get(),
362 request_->context()->network_delegate());
363 EXPECT_TRUE(job_.get());
364 EXPECT_TRUE(job_->is_waiting());
366 // We have to wait for completion of storage->FindResponseForMainRequest.
370 void Verify_MainResource_Fallback() {
371 EXPECT_FALSE(job_->is_waiting());
372 EXPECT_TRUE(job_->is_delivering_network_response());
374 // When the request is restarted, the existing job is dropped so a
375 // real network job gets created. We expect NULL here which will cause
376 // the net library to create a real job.
377 job_ = handler_->MaybeLoadResource(request_.get(),
378 request_->context()->network_delegate());
379 EXPECT_FALSE(job_.get());
381 // Simulate an http error of the real network job.
382 request_->SimulateResponseCode(500);
384 job_ = handler_->MaybeLoadFallbackForResponse(
385 request_.get(), request_->context()->network_delegate());
386 EXPECT_TRUE(job_.get());
387 EXPECT_TRUE(job_->is_delivering_appcache_response());
389 int64 cache_id = kNoCacheId;
391 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
392 EXPECT_EQ(1, cache_id);
393 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
394 EXPECT_TRUE(host_->main_resource_was_namespace_entry_);
395 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_->namespace_entry_url_);
397 EXPECT_EQ(GURL("http://blah/manifest/"),
398 host_->preferred_manifest_url());
403 // MainResource_FallbackOverride --------------------------------------------
405 void MainResource_FallbackOverride() {
406 PushNextTask(base::Bind(
407 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride,
408 base::Unretained(this)));
410 request_.reset(new MockURLRequest(GURL("http://blah/fallback-override"),
412 handler_.reset(host_->CreateRequestHandler(request_.get(),
413 ResourceType::MAIN_FRAME));
414 EXPECT_TRUE(handler_.get());
416 mock_storage()->SimulateFindMainResource(
418 GURL("http://blah/fallbackurl"),
419 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
420 1, 2, GURL("http://blah/manifest/"));
422 job_ = handler_->MaybeLoadResource(request_.get(),
423 request_->context()->network_delegate());
424 EXPECT_TRUE(job_.get());
425 EXPECT_TRUE(job_->is_waiting());
427 // We have to wait for completion of storage->FindResponseForMainRequest.
431 void Verify_MainResource_FallbackOverride() {
432 EXPECT_FALSE(job_->is_waiting());
433 EXPECT_TRUE(job_->is_delivering_network_response());
435 // When the request is restarted, the existing job is dropped so a
436 // real network job gets created. We expect NULL here which will cause
437 // the net library to create a real job.
438 job_ = handler_->MaybeLoadResource(request_.get(),
439 request_->context()->network_delegate());
440 EXPECT_FALSE(job_.get());
442 // Simulate an http error of the real network job, but with custom
443 // headers that override the fallback behavior.
444 const char kOverrideHeaders[] =
445 "HTTP/1.1 404 BOO HOO\0"
446 "x-chromium-appcache-fallback-override: disallow-fallback\0"
448 net::HttpResponseInfo info;
449 info.headers = new net::HttpResponseHeaders(
450 std::string(kOverrideHeaders, arraysize(kOverrideHeaders)));
451 request_->SimulateResponseInfo(info);
453 job_ = handler_->MaybeLoadFallbackForResponse(
454 request_.get(), request_->context()->network_delegate());
455 EXPECT_FALSE(job_.get());
460 // SubResource_Miss_WithNoCacheSelected ----------------------------------
462 void SubResource_Miss_WithNoCacheSelected() {
463 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
464 handler_.reset(host_->CreateRequestHandler(request_.get(),
465 ResourceType::SUB_RESOURCE));
467 // We avoid creating handler when possible, sub-resource requests are not
468 // subject to retrieval from an appcache when there's no associated cache.
469 EXPECT_FALSE(handler_.get());
474 // SubResource_Miss_WithCacheSelected ----------------------------------
476 void SubResource_Miss_WithCacheSelected() {
477 // A sub-resource load where the resource is not in an appcache, or
478 // in a network or fallback namespace, should result in a failed request.
479 host_->AssociateCompleteCache(MakeNewCache());
481 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
482 handler_.reset(host_->CreateRequestHandler(request_.get(),
483 ResourceType::SUB_RESOURCE));
484 EXPECT_TRUE(handler_.get());
486 job_ = handler_->MaybeLoadResource(request_.get(),
487 request_->context()->network_delegate());
488 EXPECT_TRUE(job_.get());
489 EXPECT_TRUE(job_->is_delivering_error_response());
491 AppCacheURLRequestJob* fallback_job;
492 fallback_job = handler_->MaybeLoadFallbackForRedirect(
494 request_->context()->network_delegate(),
495 GURL("http://blah/redirect"));
496 EXPECT_FALSE(fallback_job);
497 fallback_job = handler_->MaybeLoadFallbackForResponse(
498 request_.get(), request_->context()->network_delegate());
499 EXPECT_FALSE(fallback_job);
504 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
506 void SubResource_Miss_WithWaitForCacheSelection() {
507 // Precondition, the host is waiting on cache selection.
508 scoped_refptr<AppCache> cache(MakeNewCache());
509 host_->pending_selected_cache_id_ = cache->cache_id();
510 host_->set_preferred_manifest_url(cache->owning_group()->manifest_url());
512 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
513 handler_.reset(host_->CreateRequestHandler(request_.get(),
514 ResourceType::SUB_RESOURCE));
515 EXPECT_TRUE(handler_.get());
516 job_ = handler_->MaybeLoadResource(request_.get(),
517 request_->context()->network_delegate());
518 EXPECT_TRUE(job_.get());
519 EXPECT_TRUE(job_->is_waiting());
521 host_->FinishCacheSelection(cache.get(), NULL);
522 EXPECT_FALSE(job_->is_waiting());
523 EXPECT_TRUE(job_->is_delivering_error_response());
525 AppCacheURLRequestJob* fallback_job;
526 fallback_job = handler_->MaybeLoadFallbackForRedirect(
528 request_->context()->network_delegate(),
529 GURL("http://blah/redirect"));
530 EXPECT_FALSE(fallback_job);
531 fallback_job = handler_->MaybeLoadFallbackForResponse(
532 request_.get(), request_->context()->network_delegate());
533 EXPECT_FALSE(fallback_job);
538 // SubResource_Hit -----------------------------
540 void SubResource_Hit() {
541 host_->AssociateCompleteCache(MakeNewCache());
543 mock_storage()->SimulateFindSubResource(
544 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
546 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
547 handler_.reset(host_->CreateRequestHandler(request_.get(),
548 ResourceType::SUB_RESOURCE));
549 EXPECT_TRUE(handler_.get());
550 job_ = handler_->MaybeLoadResource(request_.get(),
551 request_->context()->network_delegate());
552 EXPECT_TRUE(job_.get());
553 EXPECT_TRUE(job_->is_delivering_appcache_response());
555 AppCacheURLRequestJob* fallback_job;
556 fallback_job = handler_->MaybeLoadFallbackForRedirect(
558 request_->context()->network_delegate(),
559 GURL("http://blah/redirect"));
560 EXPECT_FALSE(fallback_job);
561 fallback_job = handler_->MaybeLoadFallbackForResponse(
562 request_.get(), request_->context()->network_delegate());
563 EXPECT_FALSE(fallback_job);
568 // SubResource_RedirectFallback -----------------------------
570 void SubResource_RedirectFallback() {
571 // Redirects to resources in the a different origin are subject to
572 // fallback namespaces.
573 host_->AssociateCompleteCache(MakeNewCache());
575 mock_storage()->SimulateFindSubResource(
576 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
578 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
579 handler_.reset(host_->CreateRequestHandler(request_.get(),
580 ResourceType::SUB_RESOURCE));
581 EXPECT_TRUE(handler_.get());
582 job_ = handler_->MaybeLoadResource(request_.get(),
583 request_->context()->network_delegate());
584 EXPECT_FALSE(job_.get());
586 job_ = handler_->MaybeLoadFallbackForRedirect(
588 request_->context()->network_delegate(),
589 GURL("http://not_blah/redirect"));
590 EXPECT_TRUE(job_.get());
591 EXPECT_TRUE(job_->is_delivering_appcache_response());
593 AppCacheURLRequestJob* fallback_job;
594 fallback_job = handler_->MaybeLoadFallbackForResponse(
595 request_.get(), request_->context()->network_delegate());
596 EXPECT_FALSE(fallback_job);
601 // SubResource_NoRedirectFallback -----------------------------
603 void SubResource_NoRedirectFallback() {
604 // Redirects to resources in the same-origin are not subject to
605 // fallback namespaces.
606 host_->AssociateCompleteCache(MakeNewCache());
608 mock_storage()->SimulateFindSubResource(
609 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
611 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
612 handler_.reset(host_->CreateRequestHandler(request_.get(),
613 ResourceType::SUB_RESOURCE));
614 EXPECT_TRUE(handler_.get());
615 job_ = handler_->MaybeLoadResource(request_.get(),
616 request_->context()->network_delegate());
617 EXPECT_FALSE(job_.get());
619 AppCacheURLRequestJob* fallback_job;
620 fallback_job = handler_->MaybeLoadFallbackForRedirect(
622 request_->context()->network_delegate(),
623 GURL("http://blah/redirect"));
624 EXPECT_FALSE(fallback_job);
626 request_->SimulateResponseCode(200);
627 fallback_job = handler_->MaybeLoadFallbackForResponse(
628 request_.get(), request_->context()->network_delegate());
629 EXPECT_FALSE(fallback_job);
634 // SubResource_Network -----------------------------
636 void SubResource_Network() {
637 // A sub-resource load where the resource is in a network namespace,
638 // should result in the system using a 'real' job to do the network
640 host_->AssociateCompleteCache(MakeNewCache());
642 mock_storage()->SimulateFindSubResource(
643 AppCacheEntry(), AppCacheEntry(), true);
645 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
646 handler_.reset(host_->CreateRequestHandler(request_.get(),
647 ResourceType::SUB_RESOURCE));
648 EXPECT_TRUE(handler_.get());
649 job_ = handler_->MaybeLoadResource(request_.get(),
650 request_->context()->network_delegate());
651 EXPECT_FALSE(job_.get());
653 AppCacheURLRequestJob* fallback_job;
654 fallback_job = handler_->MaybeLoadFallbackForRedirect(
656 request_->context()->network_delegate(),
657 GURL("http://blah/redirect"));
658 EXPECT_FALSE(fallback_job);
659 fallback_job = handler_->MaybeLoadFallbackForResponse(
660 request_.get(), request_->context()->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(GURL("http://blah/"), &empty_context_));
675 handler_.reset(host_->CreateRequestHandler(request_.get(),
676 ResourceType::SUB_RESOURCE));
677 EXPECT_TRUE(handler_.get());
679 backend_impl_->UnregisterHost(1);
682 EXPECT_FALSE(handler_->MaybeLoadResource(
683 request_.get(), request_->context()->network_delegate()));
684 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
686 request_->context()->network_delegate(),
687 GURL("http://blah/redirect")));
688 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
689 request_.get(), request_->context()->network_delegate()));
694 // DestroyedHostWithWaitingJob -----------------------------
696 void DestroyedHostWithWaitingJob() {
697 // Precondition, the host is waiting on cache selection.
698 host_->pending_selected_cache_id_ = 1;
700 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
701 handler_.reset(host_->CreateRequestHandler(request_.get(),
702 ResourceType::SUB_RESOURCE));
703 EXPECT_TRUE(handler_.get());
705 job_ = handler_->MaybeLoadResource(request_.get(),
706 request_->context()->network_delegate());
707 EXPECT_TRUE(job_.get());
708 EXPECT_TRUE(job_->is_waiting());
710 backend_impl_->UnregisterHost(1);
712 EXPECT_TRUE(job_->has_been_killed());
714 EXPECT_FALSE(handler_->MaybeLoadResource(
715 request_.get(), request_->context()->network_delegate()));
716 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
718 request_->context()->network_delegate(),
719 GURL("http://blah/redirect")));
720 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
721 request_.get(), request_->context()->network_delegate()));
726 // UnsupportedScheme -----------------------------
728 void UnsupportedScheme() {
729 // Precondition, the host is waiting on cache selection.
730 host_->pending_selected_cache_id_ = 1;
732 request_.reset(new MockURLRequest(GURL("ftp://blah/"), &empty_context_));
733 handler_.reset(host_->CreateRequestHandler(request_.get(),
734 ResourceType::SUB_RESOURCE));
735 EXPECT_TRUE(handler_.get()); // we could redirect to http (conceivably)
737 EXPECT_FALSE(handler_->MaybeLoadResource(
738 request_.get(), request_->context()->network_delegate()));
739 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
741 request_->context()->network_delegate(),
742 GURL("ftp://blah/redirect")));
743 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
744 request_.get(), request_->context()->network_delegate()));
749 // CanceledRequest -----------------------------
751 void CanceledRequest() {
752 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
753 handler_.reset(host_->CreateRequestHandler(request_.get(),
754 ResourceType::MAIN_FRAME));
755 EXPECT_TRUE(handler_.get());
757 job_ = handler_->MaybeLoadResource(request_.get(),
758 request_->context()->network_delegate());
759 EXPECT_TRUE(job_.get());
760 EXPECT_TRUE(job_->is_waiting());
761 EXPECT_FALSE(job_->has_been_started());
763 mock_factory_job_ = job_.get();
765 EXPECT_TRUE(job_->has_been_started());
768 EXPECT_TRUE(job_->has_been_killed());
770 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
771 request_.get(), request_->context()->network_delegate()));
776 // WorkerRequest -----------------------------
778 void WorkerRequest() {
779 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
780 ResourceType::MAIN_FRAME));
781 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
782 ResourceType::SUB_FRAME));
783 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
784 ResourceType::SHARED_WORKER));
785 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
786 ResourceType::WORKER));
788 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
790 const int kParentHostId = host_->host_id();
791 const int kWorkerHostId = 2;
792 const int kAbandonedWorkerHostId = 3;
793 const int kNonExsitingHostId = 700;
795 backend_impl_->RegisterHost(kWorkerHostId);
796 AppCacheHost* worker_host = backend_impl_->GetHost(kWorkerHostId);
797 worker_host->SelectCacheForWorker(kParentHostId, kMockProcessId);
798 handler_.reset(worker_host->CreateRequestHandler(
799 request_.get(), ResourceType::SHARED_WORKER));
800 EXPECT_TRUE(handler_.get());
801 // Verify that the handler is associated with the parent host.
802 EXPECT_EQ(host_, handler_->host_);
804 // Create a new worker host, but associate it with a parent host that
805 // does not exists to simulate the host having been torn down.
806 backend_impl_->UnregisterHost(kWorkerHostId);
807 backend_impl_->RegisterHost(kAbandonedWorkerHostId);
808 worker_host = backend_impl_->GetHost(kAbandonedWorkerHostId);
809 EXPECT_EQ(NULL, backend_impl_->GetHost(kNonExsitingHostId));
810 worker_host->SelectCacheForWorker(kNonExsitingHostId, kMockProcessId);
811 handler_.reset(worker_host->CreateRequestHandler(
812 request_.get(), ResourceType::SHARED_WORKER));
813 EXPECT_FALSE(handler_.get());
818 // MainResource_Blocked --------------------------------------------------
820 void MainResource_Blocked() {
822 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked,
823 base::Unretained(this)));
825 request_.reset(new MockURLRequest(GURL("http://blah/"), &empty_context_));
826 handler_.reset(host_->CreateRequestHandler(request_.get(),
827 ResourceType::MAIN_FRAME));
828 EXPECT_TRUE(handler_.get());
830 mock_policy_->can_load_return_value_ = false;
831 mock_storage()->SimulateFindMainResource(
832 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
833 GURL(), AppCacheEntry(),
834 1, 2, GURL("http://blah/manifest/"));
836 job_ = handler_->MaybeLoadResource(request_.get(),
837 request_->context()->network_delegate());
838 EXPECT_TRUE(job_.get());
839 EXPECT_TRUE(job_->is_waiting());
841 // We have to wait for completion of storage->FindResponseForMainRequest.
845 void Verify_MainResource_Blocked() {
846 EXPECT_FALSE(job_->is_waiting());
847 EXPECT_FALSE(job_->is_delivering_appcache_response());
849 EXPECT_EQ(0, handler_->found_cache_id_);
850 EXPECT_EQ(0, handler_->found_group_id_);
851 EXPECT_TRUE(handler_->found_manifest_url_.is_empty());
852 EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
853 EXPECT_TRUE(host_->main_resource_blocked_);
854 EXPECT_TRUE(host_->blocked_manifest_url_ == GURL("http://blah/manifest/"));
859 // Test case helpers --------------------------------------------------
861 AppCache* MakeNewCache() {
862 AppCache* cache = new AppCache(
863 mock_storage(), mock_storage()->NewCacheId());
864 cache->set_complete(true);
865 AppCacheGroup* group = new AppCacheGroup(
866 mock_storage(), GURL("http://blah/manifest"),
867 mock_storage()->NewGroupId());
868 group->AddCache(cache);
872 MockAppCacheStorage* mock_storage() {
873 return reinterpret_cast<MockAppCacheStorage*>(mock_service_->storage());
876 // Data members --------------------------------------------------
878 scoped_ptr<base::WaitableEvent> test_finished_event_;
879 std::stack<base::Closure> task_stack_;
880 scoped_ptr<MockAppCacheService> mock_service_;
881 scoped_ptr<AppCacheBackendImpl> backend_impl_;
882 scoped_ptr<MockFrontend> mock_frontend_;
883 scoped_ptr<MockAppCachePolicy> mock_policy_;
885 net::URLRequestContext empty_context_;
886 scoped_ptr<MockURLRequest> request_;
887 scoped_ptr<AppCacheRequestHandler> handler_;
888 scoped_refptr<AppCacheURLRequestJob> job_;
889 net::URLRequest::ProtocolFactory* orig_http_factory_;
891 static scoped_ptr<base::Thread> io_thread_;
892 static net::URLRequestJob* mock_factory_job_;
896 scoped_ptr<base::Thread> AppCacheRequestHandlerTest::io_thread_;
897 net::URLRequestJob* AppCacheRequestHandlerTest::mock_factory_job_ = NULL;
899 TEST_F(AppCacheRequestHandlerTest, MainResource_Miss) {
900 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss);
903 TEST_F(AppCacheRequestHandlerTest, MainResource_Hit) {
904 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit);
907 TEST_F(AppCacheRequestHandlerTest, MainResource_Fallback) {
908 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback);
911 TEST_F(AppCacheRequestHandlerTest, MainResource_FallbackOverride) {
913 &AppCacheRequestHandlerTest::MainResource_FallbackOverride);
916 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithNoCacheSelected) {
918 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected);
921 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithCacheSelected) {
923 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected);
926 TEST_F(AppCacheRequestHandlerTest,
927 SubResource_Miss_WithWaitForCacheSelection) {
929 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection);
932 TEST_F(AppCacheRequestHandlerTest, SubResource_Hit) {
933 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit);
936 TEST_F(AppCacheRequestHandlerTest, SubResource_RedirectFallback) {
937 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback);
940 TEST_F(AppCacheRequestHandlerTest, SubResource_NoRedirectFallback) {
942 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback);
945 TEST_F(AppCacheRequestHandlerTest, SubResource_Network) {
946 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network);
949 TEST_F(AppCacheRequestHandlerTest, DestroyedHost) {
950 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost);
953 TEST_F(AppCacheRequestHandlerTest, DestroyedHostWithWaitingJob) {
954 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob);
957 TEST_F(AppCacheRequestHandlerTest, UnsupportedScheme) {
958 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme);
961 TEST_F(AppCacheRequestHandlerTest, CanceledRequest) {
962 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest);
965 TEST_F(AppCacheRequestHandlerTest, WorkerRequest) {
966 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest);
969 TEST_F(AppCacheRequestHandlerTest, MainResource_Blocked) {
970 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked);
973 } // namespace appcache