Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / appcache / appcache_request_handler_unittest.cc
blob523746d25550f75fd0ee208a3232066a408206d8
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.
5 #include <stack>
6 #include <string>
7 #include <vector>
9 #include "base/bind.h"
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"
30 namespace content {
32 static const int kMockProcessId = 1;
34 class AppCacheRequestHandlerTest : public testing::Test {
35 public:
36 class MockFrontend : public AppCacheFrontend {
37 public:
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,
52 const GURL& url,
53 int num_total,
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) {
70 SetUpTest();
71 (this->*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 {
85 public:
86 MockURLRequestJob(net::URLRequest* request,
87 net::NetworkDelegate* network_delegate,
88 int response_code)
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) {}
100 protected:
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_)
111 return;
112 *info = response_info_;
115 private:
116 int response_code_;
117 bool has_response_info_;
118 net::HttpResponseInfo response_info_;
121 class MockURLRequestJobFactory : public net::URLRequestJobFactory {
122 public:
123 MockURLRequestJobFactory() : job_(NULL) {
126 virtual ~MockURLRequestJobFactory() {
127 DCHECK(!job_);
130 void SetJob(net::URLRequestJob* job) {
131 job_ = job;
134 virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
135 const std::string& scheme,
136 net::URLRequest* request,
137 net::NetworkDelegate* network_delegate) const OVERRIDE {
138 if (job_) {
139 net::URLRequestJob* temp = job_;
140 job_ = NULL;
141 return temp;
142 } else {
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,
146 network_delegate,
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 {
160 return false;
163 private:
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(
185 FROM_HERE,
186 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper<Method>,
187 base::Unretained(this), method));
188 test_finished_event_->Wait();
191 void SetUpTest() {
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(),
200 kMockProcessId);
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());
210 job_ = NULL;
211 handler_.reset();
212 request_.reset();
213 backend_impl_.reset();
214 mock_frontend_.reset();
215 mock_service_.reset();
216 mock_policy_.reset();
217 job_factory_.reset();
218 host_ = NULL;
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(
226 FROM_HERE,
227 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound,
228 base::Unretained(this)));
231 void TestFinishedUnwound() {
232 TearDownTest();
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()) {
243 TestFinished();
244 return;
246 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
247 task_stack_.pop();
250 // MainResource_Miss --------------------------------------------------
252 void MainResource_Miss() {
253 PushNextTask(
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.
269 ScheduleNextTask();
272 void Verify_MainResource_Miss() {
273 EXPECT_FALSE(job_->is_waiting());
274 EXPECT_TRUE(job_->is_delivering_network_response());
276 int64 cache_id = kAppCacheNoCacheId;
277 GURL manifest_url;
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(
285 request_.get(),
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());
295 TestFinished();
298 // MainResource_Hit --------------------------------------------------
300 void MainResource_Hit() {
301 PushNextTask(
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.
322 ScheduleNextTask();
325 void Verify_MainResource_Hit() {
326 EXPECT_FALSE(job_->is_waiting());
327 EXPECT_TRUE(job_->is_delivering_appcache_response());
329 int64 cache_id = kAppCacheNoCacheId;
330 GURL manifest_url;
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());
344 TestFinished();
347 // MainResource_Fallback --------------------------------------------------
349 void MainResource_Fallback() {
350 PushNextTask(
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(
361 AppCacheEntry(),
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.
372 ScheduleNextTask();
375 void SimulateResponseCode(int response_code) {
376 job_factory_->SetJob(
377 new MockURLRequestJob(
378 request_.get(),
379 request_->context()->network_delegate(),
380 response_code));
381 request_->Start();
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(
390 request_.get(),
391 request_->context()->network_delegate(), info));
392 request_->Start();
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;
415 GURL manifest_url;
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());
425 TestFinished();
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,
437 &delegate_, NULL);
438 handler_.reset(host_->CreateRequestHandler(request_.get(),
439 RESOURCE_TYPE_MAIN_FRAME));
440 EXPECT_TRUE(handler_.get());
442 mock_storage()->SimulateFindMainResource(
443 AppCacheEntry(),
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.
454 ScheduleNextTask();
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"
473 "\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());
483 TestFinished();
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());
498 TestFinished();
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(
521 request_.get(),
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);
529 TestFinished();
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(
556 request_.get(),
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);
564 TestFinished();
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(
587 request_.get(),
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);
595 TestFinished();
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(
618 request_.get(),
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);
629 TestFinished();
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(
653 request_.get(),
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);
663 TestFinished();
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
671 // retrieval.
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(
688 request_.get(),
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);
696 TestFinished();
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);
714 host_ = NULL;
716 EXPECT_FALSE(handler_->MaybeLoadResource(
717 request_.get(), request_->context()->network_delegate()));
718 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
719 request_.get(),
720 request_->context()->network_delegate(),
721 GURL("http://blah/redirect")));
722 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
723 request_.get(), request_->context()->network_delegate()));
725 TestFinished();
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);
746 host_ = NULL;
747 EXPECT_TRUE(job_->has_been_killed());
749 EXPECT_FALSE(handler_->MaybeLoadResource(
750 request_.get(), request_->context()->network_delegate()));
751 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
752 request_.get(),
753 request_->context()->network_delegate(),
754 GURL("http://blah/redirect")));
755 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
756 request_.get(), request_->context()->network_delegate()));
758 TestFinished();
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(
776 request_.get(),
777 request_->context()->network_delegate(),
778 GURL("ftp://blah/redirect")));
779 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
780 request_.get(), request_->context()->network_delegate()));
782 TestFinished();
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());
801 request_->Start();
802 EXPECT_TRUE(job_->has_been_started());
804 request_->Cancel();
805 EXPECT_TRUE(job_->has_been_killed());
807 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
808 request_.get(), request_->context()->network_delegate()));
810 TestFinished();
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());
853 TestFinished();
856 // MainResource_Blocked --------------------------------------------------
858 void MainResource_Blocked() {
859 PushNextTask(
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.
881 ScheduleNextTask();
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/"));
895 TestFinished();
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);
908 return 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_;
923 AppCacheHost* host_;
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_;
934 // static
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) {
950 RunTestOnIOThread(
951 &AppCacheRequestHandlerTest::MainResource_FallbackOverride);
954 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithNoCacheSelected) {
955 RunTestOnIOThread(
956 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected);
959 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithCacheSelected) {
960 RunTestOnIOThread(
961 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected);
964 TEST_F(AppCacheRequestHandlerTest,
965 SubResource_Miss_WithWaitForCacheSelection) {
966 RunTestOnIOThread(
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) {
979 RunTestOnIOThread(
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