Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / appcache / appcache_request_handler_unittest.cc
blobf05fed295449569d811ed8024927bb4f3ab01ed9
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 void OnCacheSelected(int host_id, const AppCacheInfo& info) override {}
40 void OnStatusChanged(const std::vector<int>& host_ids,
41 AppCacheStatus status) override {}
43 void OnEventRaised(const std::vector<int>& host_ids,
44 AppCacheEventID event_id) override {}
46 void OnErrorEventRaised(const std::vector<int>& host_ids,
47 const AppCacheErrorDetails& details) override {}
49 void OnProgressEventRaised(const std::vector<int>& host_ids,
50 const GURL& url,
51 int num_total,
52 int num_complete) override {}
54 void OnLogMessage(int host_id,
55 AppCacheLogLevel log_level,
56 const std::string& message) override {}
58 void OnContentBlocked(int host_id, const GURL& manifest_url) override {}
61 // Helper callback to run a test on our io_thread. The io_thread is spun up
62 // once and reused for all tests.
63 template <class Method>
64 void MethodWrapper(Method method) {
65 SetUpTest();
66 (this->*method)();
69 // Subclasses to simulate particular responses so test cases can
70 // exercise fallback code paths.
72 class MockURLRequestDelegate : public net::URLRequest::Delegate {
73 void OnResponseStarted(net::URLRequest* request) override {}
74 void OnReadCompleted(net::URLRequest* request, int bytes_read) override {}
77 class MockURLRequestJob : public net::URLRequestJob {
78 public:
79 MockURLRequestJob(net::URLRequest* request,
80 net::NetworkDelegate* network_delegate,
81 int response_code)
82 : net::URLRequestJob(request, network_delegate),
83 response_code_(response_code),
84 has_response_info_(false) {}
85 MockURLRequestJob(net::URLRequest* request,
86 net::NetworkDelegate* network_delegate,
87 const net::HttpResponseInfo& info)
88 : net::URLRequestJob(request, network_delegate),
89 response_code_(info.headers->response_code()),
90 has_response_info_(true),
91 response_info_(info) {}
93 protected:
94 ~MockURLRequestJob() override {}
95 void Start() override { NotifyHeadersComplete(); }
96 int GetResponseCode() const override { return response_code_; }
97 void GetResponseInfo(net::HttpResponseInfo* info) override {
98 if (!has_response_info_)
99 return;
100 *info = response_info_;
103 private:
104 int response_code_;
105 bool has_response_info_;
106 net::HttpResponseInfo response_info_;
109 class MockURLRequestJobFactory : public net::URLRequestJobFactory {
110 public:
111 MockURLRequestJobFactory() : job_(NULL) {
114 ~MockURLRequestJobFactory() override { DCHECK(!job_); }
116 void SetJob(net::URLRequestJob* job) {
117 job_ = job;
120 net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
121 const std::string& scheme,
122 net::URLRequest* request,
123 net::NetworkDelegate* network_delegate) const override {
124 if (job_) {
125 net::URLRequestJob* temp = job_;
126 job_ = NULL;
127 return temp;
128 } else {
129 // Some of these tests trigger UpdateJobs which start URLRequests.
130 // We short circuit those be returning error jobs.
131 return new net::URLRequestErrorJob(request,
132 network_delegate,
133 net::ERR_INTERNET_DISCONNECTED);
137 net::URLRequestJob* MaybeInterceptRedirect(
138 net::URLRequest* request,
139 net::NetworkDelegate* network_delegate,
140 const GURL& location) const override {
141 return nullptr;
144 net::URLRequestJob* MaybeInterceptResponse(
145 net::URLRequest* request,
146 net::NetworkDelegate* network_delegate) const override {
147 return nullptr;
150 bool IsHandledProtocol(const std::string& scheme) const override {
151 return scheme == "http";
154 bool IsHandledURL(const GURL& url) const override {
155 return url.SchemeIs("http");
158 bool IsSafeRedirectTarget(const GURL& location) const override {
159 return false;
162 private:
163 mutable net::URLRequestJob* job_;
166 static void SetUpTestCase() {
167 io_thread_.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
168 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
169 io_thread_->StartWithOptions(options);
172 static void TearDownTestCase() {
173 io_thread_.reset(NULL);
176 // Test harness --------------------------------------------------
178 AppCacheRequestHandlerTest() : host_(NULL) {}
180 template <class Method>
181 void RunTestOnIOThread(Method method) {
182 test_finished_event_ .reset(new base::WaitableEvent(false, false));
183 io_thread_->message_loop()->PostTask(
184 FROM_HERE,
185 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper<Method>,
186 base::Unretained(this), method));
187 test_finished_event_->Wait();
190 void SetUpTest() {
191 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
192 mock_service_.reset(new MockAppCacheService);
193 mock_service_->set_request_context(&empty_context_);
194 mock_policy_.reset(new MockAppCachePolicy);
195 mock_service_->set_appcache_policy(mock_policy_.get());
196 mock_frontend_.reset(new MockFrontend);
197 backend_impl_.reset(new AppCacheBackendImpl);
198 backend_impl_->Initialize(mock_service_.get(), mock_frontend_.get(),
199 kMockProcessId);
200 const int kHostId = 1;
201 backend_impl_->RegisterHost(kHostId);
202 host_ = backend_impl_->GetHost(kHostId);
203 job_factory_.reset(new MockURLRequestJobFactory());
204 empty_context_.set_job_factory(job_factory_.get());
207 void TearDownTest() {
208 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
209 job_ = NULL;
210 handler_.reset();
211 request_.reset();
212 backend_impl_.reset();
213 mock_frontend_.reset();
214 mock_service_.reset();
215 mock_policy_.reset();
216 job_factory_.reset();
217 host_ = NULL;
220 void TestFinished() {
221 // We unwind the stack prior to finishing up to let stack
222 // based objects get deleted.
223 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
224 base::MessageLoop::current()->PostTask(
225 FROM_HERE,
226 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound,
227 base::Unretained(this)));
230 void TestFinishedUnwound() {
231 TearDownTest();
232 test_finished_event_->Signal();
235 void PushNextTask(const base::Closure& task) {
236 task_stack_.push(task);
239 void ScheduleNextTask() {
240 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
241 if (task_stack_.empty()) {
242 TestFinished();
243 return;
245 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
246 task_stack_.pop();
249 // MainResource_Miss --------------------------------------------------
251 void MainResource_Miss() {
252 PushNextTask(
253 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss,
254 base::Unretained(this)));
256 request_ = empty_context_.CreateRequest(
257 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
258 handler_.reset(host_->CreateRequestHandler(request_.get(),
259 RESOURCE_TYPE_MAIN_FRAME,
260 false));
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_);
307 handler_.reset(host_->CreateRequestHandler(request_.get(),
308 RESOURCE_TYPE_MAIN_FRAME,
309 false));
310 EXPECT_TRUE(handler_.get());
312 mock_storage()->SimulateFindMainResource(
313 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
314 GURL(), AppCacheEntry(),
315 1, 2, GURL("http://blah/manifest/"));
317 job_ = handler_->MaybeLoadResource(request_.get(),
318 request_->context()->network_delegate());
319 EXPECT_TRUE(job_.get());
320 EXPECT_TRUE(job_->is_waiting());
322 // We have to wait for completion of storage->FindResponseForMainRequest.
323 ScheduleNextTask();
326 void Verify_MainResource_Hit() {
327 EXPECT_FALSE(job_->is_waiting());
328 EXPECT_TRUE(job_->is_delivering_appcache_response());
330 int64 cache_id = kAppCacheNoCacheId;
331 GURL manifest_url;
332 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
333 EXPECT_EQ(1, cache_id);
334 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
335 EXPECT_EQ(2, handler_->found_group_id_);
337 AppCacheURLRequestJob* fallback_job;
338 fallback_job = handler_->MaybeLoadFallbackForResponse(
339 request_.get(), request_->context()->network_delegate());
340 EXPECT_FALSE(fallback_job);
342 EXPECT_EQ(GURL("http://blah/manifest/"),
343 host_->preferred_manifest_url());
345 TestFinished();
348 // MainResource_Fallback --------------------------------------------------
350 void MainResource_Fallback() {
351 PushNextTask(
352 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback,
353 base::Unretained(this)));
355 request_ = empty_context_.CreateRequest(
356 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
357 handler_.reset(host_->CreateRequestHandler(request_.get(),
358 RESOURCE_TYPE_MAIN_FRAME,
359 false));
360 EXPECT_TRUE(handler_.get());
362 mock_storage()->SimulateFindMainResource(
363 AppCacheEntry(),
364 GURL("http://blah/fallbackurl"),
365 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
366 1, 2, GURL("http://blah/manifest/"));
368 job_ = handler_->MaybeLoadResource(request_.get(),
369 request_->context()->network_delegate());
370 EXPECT_TRUE(job_.get());
371 EXPECT_TRUE(job_->is_waiting());
373 // We have to wait for completion of storage->FindResponseForMainRequest.
374 ScheduleNextTask();
377 void SimulateResponseCode(int response_code) {
378 job_factory_->SetJob(
379 new MockURLRequestJob(
380 request_.get(),
381 request_->context()->network_delegate(),
382 response_code));
383 request_->Start();
384 // All our simulation needs to satisfy are the following two DCHECKs
385 DCHECK(request_->status().is_success());
386 DCHECK_EQ(response_code, request_->GetResponseCode());
389 void SimulateResponseInfo(const net::HttpResponseInfo& info) {
390 job_factory_->SetJob(
391 new MockURLRequestJob(
392 request_.get(),
393 request_->context()->network_delegate(), info));
394 request_->Start();
397 void Verify_MainResource_Fallback() {
398 EXPECT_FALSE(job_->is_waiting());
399 EXPECT_TRUE(job_->is_delivering_network_response());
401 // When the request is restarted, the existing job is dropped so a
402 // real network job gets created. We expect NULL here which will cause
403 // the net library to create a real job.
404 job_ = handler_->MaybeLoadResource(request_.get(),
405 request_->context()->network_delegate());
406 EXPECT_FALSE(job_.get());
408 // Simulate an http error of the real network job.
409 SimulateResponseCode(500);
411 job_ = handler_->MaybeLoadFallbackForResponse(
412 request_.get(), request_->context()->network_delegate());
413 EXPECT_TRUE(job_.get());
414 EXPECT_TRUE(job_->is_delivering_appcache_response());
416 int64 cache_id = kAppCacheNoCacheId;
417 GURL manifest_url;
418 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
419 EXPECT_EQ(1, cache_id);
420 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
421 EXPECT_TRUE(host_->main_resource_was_namespace_entry_);
422 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_->namespace_entry_url_);
424 EXPECT_EQ(GURL("http://blah/manifest/"),
425 host_->preferred_manifest_url());
427 TestFinished();
430 // MainResource_FallbackOverride --------------------------------------------
432 void MainResource_FallbackOverride() {
433 PushNextTask(base::Bind(
434 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride,
435 base::Unretained(this)));
437 request_ = empty_context_.CreateRequest(
438 GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY,
439 &delegate_);
440 handler_.reset(host_->CreateRequestHandler(request_.get(),
441 RESOURCE_TYPE_MAIN_FRAME,
442 false));
443 EXPECT_TRUE(handler_.get());
445 mock_storage()->SimulateFindMainResource(
446 AppCacheEntry(),
447 GURL("http://blah/fallbackurl"),
448 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
449 1, 2, GURL("http://blah/manifest/"));
451 job_ = handler_->MaybeLoadResource(request_.get(),
452 request_->context()->network_delegate());
453 EXPECT_TRUE(job_.get());
454 EXPECT_TRUE(job_->is_waiting());
456 // We have to wait for completion of storage->FindResponseForMainRequest.
457 ScheduleNextTask();
460 void Verify_MainResource_FallbackOverride() {
461 EXPECT_FALSE(job_->is_waiting());
462 EXPECT_TRUE(job_->is_delivering_network_response());
464 // When the request is restarted, the existing job is dropped so a
465 // real network job gets created. We expect NULL here which will cause
466 // the net library to create a real job.
467 job_ = handler_->MaybeLoadResource(request_.get(),
468 request_->context()->network_delegate());
469 EXPECT_FALSE(job_.get());
471 // Simulate an http error of the real network job, but with custom
472 // headers that override the fallback behavior.
473 const char kOverrideHeaders[] =
474 "HTTP/1.1 404 BOO HOO\0"
475 "x-chromium-appcache-fallback-override: disallow-fallback\0"
476 "\0";
477 net::HttpResponseInfo info;
478 info.headers = new net::HttpResponseHeaders(
479 std::string(kOverrideHeaders, arraysize(kOverrideHeaders)));
480 SimulateResponseInfo(info);
482 job_ = handler_->MaybeLoadFallbackForResponse(
483 request_.get(), request_->context()->network_delegate());
484 EXPECT_FALSE(job_.get());
486 TestFinished();
489 // SubResource_Miss_WithNoCacheSelected ----------------------------------
491 void SubResource_Miss_WithNoCacheSelected() {
492 request_ = empty_context_.CreateRequest(
493 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
494 handler_.reset(host_->CreateRequestHandler(request_.get(),
495 RESOURCE_TYPE_SUB_RESOURCE,
496 false));
498 // We avoid creating handler when possible, sub-resource requests are not
499 // subject to retrieval from an appcache when there's no associated cache.
500 EXPECT_FALSE(handler_.get());
502 TestFinished();
505 // SubResource_Miss_WithCacheSelected ----------------------------------
507 void SubResource_Miss_WithCacheSelected() {
508 // A sub-resource load where the resource is not in an appcache, or
509 // in a network or fallback namespace, should result in a failed request.
510 host_->AssociateCompleteCache(MakeNewCache());
512 request_ = empty_context_.CreateRequest(
513 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
514 handler_.reset(host_->CreateRequestHandler(request_.get(),
515 RESOURCE_TYPE_SUB_RESOURCE,
516 false));
517 EXPECT_TRUE(handler_.get());
519 job_ = handler_->MaybeLoadResource(request_.get(),
520 request_->context()->network_delegate());
521 EXPECT_TRUE(job_.get());
522 EXPECT_TRUE(job_->is_delivering_error_response());
524 AppCacheURLRequestJob* fallback_job;
525 fallback_job = handler_->MaybeLoadFallbackForRedirect(
526 request_.get(),
527 request_->context()->network_delegate(),
528 GURL("http://blah/redirect"));
529 EXPECT_FALSE(fallback_job);
530 fallback_job = handler_->MaybeLoadFallbackForResponse(
531 request_.get(), request_->context()->network_delegate());
532 EXPECT_FALSE(fallback_job);
534 TestFinished();
537 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
539 void SubResource_Miss_WithWaitForCacheSelection() {
540 // Precondition, the host is waiting on cache selection.
541 scoped_refptr<AppCache> cache(MakeNewCache());
542 host_->pending_selected_cache_id_ = cache->cache_id();
543 host_->set_preferred_manifest_url(cache->owning_group()->manifest_url());
545 request_ = empty_context_.CreateRequest(
546 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
547 handler_.reset(host_->CreateRequestHandler(request_.get(),
548 RESOURCE_TYPE_SUB_RESOURCE,
549 false));
550 EXPECT_TRUE(handler_.get());
551 job_ = handler_->MaybeLoadResource(request_.get(),
552 request_->context()->network_delegate());
553 EXPECT_TRUE(job_.get());
554 EXPECT_TRUE(job_->is_waiting());
556 host_->FinishCacheSelection(cache.get(), NULL);
557 EXPECT_FALSE(job_->is_waiting());
558 EXPECT_TRUE(job_->is_delivering_error_response());
560 AppCacheURLRequestJob* fallback_job;
561 fallback_job = handler_->MaybeLoadFallbackForRedirect(
562 request_.get(),
563 request_->context()->network_delegate(),
564 GURL("http://blah/redirect"));
565 EXPECT_FALSE(fallback_job);
566 fallback_job = handler_->MaybeLoadFallbackForResponse(
567 request_.get(), request_->context()->network_delegate());
568 EXPECT_FALSE(fallback_job);
570 TestFinished();
573 // SubResource_Hit -----------------------------
575 void SubResource_Hit() {
576 host_->AssociateCompleteCache(MakeNewCache());
578 mock_storage()->SimulateFindSubResource(
579 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
581 request_ = empty_context_.CreateRequest(
582 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
583 handler_.reset(host_->CreateRequestHandler(request_.get(),
584 RESOURCE_TYPE_SUB_RESOURCE,
585 false));
586 EXPECT_TRUE(handler_.get());
587 job_ = handler_->MaybeLoadResource(request_.get(),
588 request_->context()->network_delegate());
589 EXPECT_TRUE(job_.get());
590 EXPECT_TRUE(job_->is_delivering_appcache_response());
592 AppCacheURLRequestJob* fallback_job;
593 fallback_job = handler_->MaybeLoadFallbackForRedirect(
594 request_.get(),
595 request_->context()->network_delegate(),
596 GURL("http://blah/redirect"));
597 EXPECT_FALSE(fallback_job);
598 fallback_job = handler_->MaybeLoadFallbackForResponse(
599 request_.get(), request_->context()->network_delegate());
600 EXPECT_FALSE(fallback_job);
602 TestFinished();
605 // SubResource_RedirectFallback -----------------------------
607 void SubResource_RedirectFallback() {
608 // Redirects to resources in the a different origin are subject to
609 // fallback namespaces.
610 host_->AssociateCompleteCache(MakeNewCache());
612 mock_storage()->SimulateFindSubResource(
613 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
615 request_ = empty_context_.CreateRequest(
616 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
617 handler_.reset(host_->CreateRequestHandler(request_.get(),
618 RESOURCE_TYPE_SUB_RESOURCE,
619 false));
620 EXPECT_TRUE(handler_.get());
621 job_ = handler_->MaybeLoadResource(request_.get(),
622 request_->context()->network_delegate());
623 EXPECT_FALSE(job_.get());
625 job_ = handler_->MaybeLoadFallbackForRedirect(
626 request_.get(),
627 request_->context()->network_delegate(),
628 GURL("http://not_blah/redirect"));
629 EXPECT_TRUE(job_.get());
630 EXPECT_TRUE(job_->is_delivering_appcache_response());
632 AppCacheURLRequestJob* fallback_job;
633 fallback_job = handler_->MaybeLoadFallbackForResponse(
634 request_.get(), request_->context()->network_delegate());
635 EXPECT_FALSE(fallback_job);
637 TestFinished();
640 // SubResource_NoRedirectFallback -----------------------------
642 void SubResource_NoRedirectFallback() {
643 // Redirects to resources in the same-origin are not subject to
644 // fallback namespaces.
645 host_->AssociateCompleteCache(MakeNewCache());
647 mock_storage()->SimulateFindSubResource(
648 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
650 request_ = empty_context_.CreateRequest(
651 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
652 handler_.reset(host_->CreateRequestHandler(request_.get(),
653 RESOURCE_TYPE_SUB_RESOURCE,
654 false));
655 EXPECT_TRUE(handler_.get());
656 job_ = handler_->MaybeLoadResource(request_.get(),
657 request_->context()->network_delegate());
658 EXPECT_FALSE(job_.get());
660 AppCacheURLRequestJob* fallback_job;
661 fallback_job = handler_->MaybeLoadFallbackForRedirect(
662 request_.get(),
663 request_->context()->network_delegate(),
664 GURL("http://blah/redirect"));
665 EXPECT_FALSE(fallback_job);
667 SimulateResponseCode(200);
668 fallback_job = handler_->MaybeLoadFallbackForResponse(
669 request_.get(), request_->context()->network_delegate());
670 EXPECT_FALSE(fallback_job);
672 TestFinished();
675 // SubResource_Network -----------------------------
677 void SubResource_Network() {
678 // A sub-resource load where the resource is in a network namespace,
679 // should result in the system using a 'real' job to do the network
680 // retrieval.
681 host_->AssociateCompleteCache(MakeNewCache());
683 mock_storage()->SimulateFindSubResource(
684 AppCacheEntry(), AppCacheEntry(), true);
686 request_ = empty_context_.CreateRequest(
687 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
688 handler_.reset(host_->CreateRequestHandler(request_.get(),
689 RESOURCE_TYPE_SUB_RESOURCE,
690 false));
691 EXPECT_TRUE(handler_.get());
692 job_ = handler_->MaybeLoadResource(request_.get(),
693 request_->context()->network_delegate());
694 EXPECT_FALSE(job_.get());
696 AppCacheURLRequestJob* fallback_job;
697 fallback_job = handler_->MaybeLoadFallbackForRedirect(
698 request_.get(),
699 request_->context()->network_delegate(),
700 GURL("http://blah/redirect"));
701 EXPECT_FALSE(fallback_job);
702 fallback_job = handler_->MaybeLoadFallbackForResponse(
703 request_.get(), request_->context()->network_delegate());
704 EXPECT_FALSE(fallback_job);
706 TestFinished();
709 // DestroyedHost -----------------------------
711 void DestroyedHost() {
712 host_->AssociateCompleteCache(MakeNewCache());
714 mock_storage()->SimulateFindSubResource(
715 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
717 request_ = empty_context_.CreateRequest(
718 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
719 handler_.reset(host_->CreateRequestHandler(request_.get(),
720 RESOURCE_TYPE_SUB_RESOURCE,
721 false));
722 EXPECT_TRUE(handler_.get());
724 backend_impl_->UnregisterHost(1);
725 host_ = NULL;
727 EXPECT_FALSE(handler_->MaybeLoadResource(
728 request_.get(), request_->context()->network_delegate()));
729 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
730 request_.get(),
731 request_->context()->network_delegate(),
732 GURL("http://blah/redirect")));
733 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
734 request_.get(), request_->context()->network_delegate()));
736 TestFinished();
739 // DestroyedHostWithWaitingJob -----------------------------
741 void DestroyedHostWithWaitingJob() {
742 // Precondition, the host is waiting on cache selection.
743 host_->pending_selected_cache_id_ = 1;
745 request_ = empty_context_.CreateRequest(
746 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
747 handler_.reset(host_->CreateRequestHandler(request_.get(),
748 RESOURCE_TYPE_SUB_RESOURCE,
749 false));
750 EXPECT_TRUE(handler_.get());
752 job_ = handler_->MaybeLoadResource(request_.get(),
753 request_->context()->network_delegate());
754 EXPECT_TRUE(job_.get());
755 EXPECT_TRUE(job_->is_waiting());
757 backend_impl_->UnregisterHost(1);
758 host_ = NULL;
759 EXPECT_TRUE(job_->has_been_killed());
761 EXPECT_FALSE(handler_->MaybeLoadResource(
762 request_.get(), request_->context()->network_delegate()));
763 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
764 request_.get(),
765 request_->context()->network_delegate(),
766 GURL("http://blah/redirect")));
767 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
768 request_.get(), request_->context()->network_delegate()));
770 TestFinished();
773 // UnsupportedScheme -----------------------------
775 void UnsupportedScheme() {
776 // Precondition, the host is waiting on cache selection.
777 host_->pending_selected_cache_id_ = 1;
779 request_ = empty_context_.CreateRequest(
780 GURL("ftp://blah/"), net::DEFAULT_PRIORITY, &delegate_);
781 handler_.reset(host_->CreateRequestHandler(request_.get(),
782 RESOURCE_TYPE_SUB_RESOURCE,
783 false));
784 EXPECT_TRUE(handler_.get()); // we could redirect to http (conceivably)
786 EXPECT_FALSE(handler_->MaybeLoadResource(
787 request_.get(), request_->context()->network_delegate()));
788 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
789 request_.get(),
790 request_->context()->network_delegate(),
791 GURL("ftp://blah/redirect")));
792 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
793 request_.get(), request_->context()->network_delegate()));
795 TestFinished();
798 // CanceledRequest -----------------------------
800 void CanceledRequest() {
801 request_ = empty_context_.CreateRequest(
802 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
803 handler_.reset(host_->CreateRequestHandler(request_.get(),
804 RESOURCE_TYPE_MAIN_FRAME,
805 false));
806 EXPECT_TRUE(handler_.get());
808 job_ = handler_->MaybeLoadResource(request_.get(),
809 request_->context()->network_delegate());
810 EXPECT_TRUE(job_.get());
811 EXPECT_TRUE(job_->is_waiting());
812 EXPECT_FALSE(job_->has_been_started());
814 job_factory_->SetJob(job_.get());
815 request_->Start();
816 EXPECT_TRUE(job_->has_been_started());
818 request_->Cancel();
819 EXPECT_TRUE(job_->has_been_killed());
821 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
822 request_.get(), request_->context()->network_delegate()));
824 TestFinished();
827 // WorkerRequest -----------------------------
829 void WorkerRequest() {
830 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
831 RESOURCE_TYPE_MAIN_FRAME));
832 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
833 RESOURCE_TYPE_SUB_FRAME));
834 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
835 RESOURCE_TYPE_SHARED_WORKER));
836 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
837 RESOURCE_TYPE_WORKER));
839 request_ = empty_context_.CreateRequest(
840 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
842 const int kParentHostId = host_->host_id();
843 const int kWorkerHostId = 2;
844 const int kAbandonedWorkerHostId = 3;
845 const int kNonExsitingHostId = 700;
847 backend_impl_->RegisterHost(kWorkerHostId);
848 AppCacheHost* worker_host = backend_impl_->GetHost(kWorkerHostId);
849 worker_host->SelectCacheForWorker(kParentHostId, kMockProcessId);
850 handler_.reset(worker_host->CreateRequestHandler(
851 request_.get(), RESOURCE_TYPE_SHARED_WORKER, false));
852 EXPECT_TRUE(handler_.get());
853 // Verify that the handler is associated with the parent host.
854 EXPECT_EQ(host_, handler_->host_);
856 // Create a new worker host, but associate it with a parent host that
857 // does not exists to simulate the host having been torn down.
858 backend_impl_->UnregisterHost(kWorkerHostId);
859 backend_impl_->RegisterHost(kAbandonedWorkerHostId);
860 worker_host = backend_impl_->GetHost(kAbandonedWorkerHostId);
861 EXPECT_EQ(NULL, backend_impl_->GetHost(kNonExsitingHostId));
862 worker_host->SelectCacheForWorker(kNonExsitingHostId, kMockProcessId);
863 handler_.reset(worker_host->CreateRequestHandler(
864 request_.get(), RESOURCE_TYPE_SHARED_WORKER, false));
865 EXPECT_FALSE(handler_.get());
867 TestFinished();
870 // MainResource_Blocked --------------------------------------------------
872 void MainResource_Blocked() {
873 PushNextTask(
874 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked,
875 base::Unretained(this)));
877 request_ = empty_context_.CreateRequest(
878 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
879 handler_.reset(host_->CreateRequestHandler(request_.get(),
880 RESOURCE_TYPE_MAIN_FRAME,
881 false));
882 EXPECT_TRUE(handler_.get());
884 mock_policy_->can_load_return_value_ = false;
885 mock_storage()->SimulateFindMainResource(
886 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
887 GURL(), AppCacheEntry(),
888 1, 2, GURL("http://blah/manifest/"));
890 job_ = handler_->MaybeLoadResource(request_.get(),
891 request_->context()->network_delegate());
892 EXPECT_TRUE(job_.get());
893 EXPECT_TRUE(job_->is_waiting());
895 // We have to wait for completion of storage->FindResponseForMainRequest.
896 ScheduleNextTask();
899 void Verify_MainResource_Blocked() {
900 EXPECT_FALSE(job_->is_waiting());
901 EXPECT_FALSE(job_->is_delivering_appcache_response());
903 EXPECT_EQ(0, handler_->found_cache_id_);
904 EXPECT_EQ(0, handler_->found_group_id_);
905 EXPECT_TRUE(handler_->found_manifest_url_.is_empty());
906 EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
907 EXPECT_TRUE(host_->main_resource_blocked_);
908 EXPECT_TRUE(host_->blocked_manifest_url_ == GURL("http://blah/manifest/"));
910 TestFinished();
913 // Test case helpers --------------------------------------------------
915 AppCache* MakeNewCache() {
916 AppCache* cache = new AppCache(
917 mock_storage(), mock_storage()->NewCacheId());
918 cache->set_complete(true);
919 AppCacheGroup* group = new AppCacheGroup(
920 mock_storage(), GURL("http://blah/manifest"),
921 mock_storage()->NewGroupId());
922 group->AddCache(cache);
923 return cache;
926 MockAppCacheStorage* mock_storage() {
927 return reinterpret_cast<MockAppCacheStorage*>(mock_service_->storage());
930 // Data members --------------------------------------------------
932 scoped_ptr<base::WaitableEvent> test_finished_event_;
933 std::stack<base::Closure> task_stack_;
934 scoped_ptr<MockAppCacheService> mock_service_;
935 scoped_ptr<AppCacheBackendImpl> backend_impl_;
936 scoped_ptr<MockFrontend> mock_frontend_;
937 scoped_ptr<MockAppCachePolicy> mock_policy_;
938 AppCacheHost* host_;
939 net::URLRequestContext empty_context_;
940 scoped_ptr<MockURLRequestJobFactory> job_factory_;
941 MockURLRequestDelegate delegate_;
942 scoped_ptr<net::URLRequest> request_;
943 scoped_ptr<AppCacheRequestHandler> handler_;
944 scoped_refptr<AppCacheURLRequestJob> job_;
946 static scoped_ptr<base::Thread> io_thread_;
949 // static
950 scoped_ptr<base::Thread> AppCacheRequestHandlerTest::io_thread_;
952 TEST_F(AppCacheRequestHandlerTest, MainResource_Miss) {
953 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss);
956 TEST_F(AppCacheRequestHandlerTest, MainResource_Hit) {
957 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit);
960 TEST_F(AppCacheRequestHandlerTest, MainResource_Fallback) {
961 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback);
964 TEST_F(AppCacheRequestHandlerTest, MainResource_FallbackOverride) {
965 RunTestOnIOThread(
966 &AppCacheRequestHandlerTest::MainResource_FallbackOverride);
969 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithNoCacheSelected) {
970 RunTestOnIOThread(
971 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected);
974 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithCacheSelected) {
975 RunTestOnIOThread(
976 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected);
979 TEST_F(AppCacheRequestHandlerTest,
980 SubResource_Miss_WithWaitForCacheSelection) {
981 RunTestOnIOThread(
982 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection);
985 TEST_F(AppCacheRequestHandlerTest, SubResource_Hit) {
986 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit);
989 TEST_F(AppCacheRequestHandlerTest, SubResource_RedirectFallback) {
990 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback);
993 TEST_F(AppCacheRequestHandlerTest, SubResource_NoRedirectFallback) {
994 RunTestOnIOThread(
995 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback);
998 TEST_F(AppCacheRequestHandlerTest, SubResource_Network) {
999 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network);
1002 TEST_F(AppCacheRequestHandlerTest, DestroyedHost) {
1003 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost);
1006 TEST_F(AppCacheRequestHandlerTest, DestroyedHostWithWaitingJob) {
1007 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob);
1010 TEST_F(AppCacheRequestHandlerTest, UnsupportedScheme) {
1011 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme);
1014 TEST_F(AppCacheRequestHandlerTest, CanceledRequest) {
1015 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest);
1018 TEST_F(AppCacheRequestHandlerTest, WorkerRequest) {
1019 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest);
1022 TEST_F(AppCacheRequestHandlerTest, MainResource_Blocked) {
1023 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked);
1026 } // namespace content