cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / appcache / appcache_request_handler_unittest.cc
blob5d53a8b8a339029185d53082314f91f238c44854
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 bool IsHandledProtocol(const std::string& scheme) const override {
138 return scheme == "http";
141 bool IsHandledURL(const GURL& url) const override {
142 return url.SchemeIs("http");
145 bool IsSafeRedirectTarget(const GURL& location) const override {
146 return false;
149 private:
150 mutable net::URLRequestJob* job_;
153 static void SetUpTestCase() {
154 io_thread_.reset(new base::Thread("AppCacheRequestHandlerTest Thread"));
155 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
156 io_thread_->StartWithOptions(options);
159 static void TearDownTestCase() {
160 io_thread_.reset(NULL);
163 // Test harness --------------------------------------------------
165 AppCacheRequestHandlerTest() : host_(NULL) {}
167 template <class Method>
168 void RunTestOnIOThread(Method method) {
169 test_finished_event_ .reset(new base::WaitableEvent(false, false));
170 io_thread_->message_loop()->PostTask(
171 FROM_HERE,
172 base::Bind(&AppCacheRequestHandlerTest::MethodWrapper<Method>,
173 base::Unretained(this), method));
174 test_finished_event_->Wait();
177 void SetUpTest() {
178 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
179 mock_service_.reset(new MockAppCacheService);
180 mock_service_->set_request_context(&empty_context_);
181 mock_policy_.reset(new MockAppCachePolicy);
182 mock_service_->set_appcache_policy(mock_policy_.get());
183 mock_frontend_.reset(new MockFrontend);
184 backend_impl_.reset(new AppCacheBackendImpl);
185 backend_impl_->Initialize(mock_service_.get(), mock_frontend_.get(),
186 kMockProcessId);
187 const int kHostId = 1;
188 backend_impl_->RegisterHost(kHostId);
189 host_ = backend_impl_->GetHost(kHostId);
190 job_factory_.reset(new MockURLRequestJobFactory());
191 empty_context_.set_job_factory(job_factory_.get());
194 void TearDownTest() {
195 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
196 job_ = NULL;
197 handler_.reset();
198 request_.reset();
199 backend_impl_.reset();
200 mock_frontend_.reset();
201 mock_service_.reset();
202 mock_policy_.reset();
203 job_factory_.reset();
204 host_ = NULL;
207 void TestFinished() {
208 // We unwind the stack prior to finishing up to let stack
209 // based objects get deleted.
210 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
211 base::MessageLoop::current()->PostTask(
212 FROM_HERE,
213 base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound,
214 base::Unretained(this)));
217 void TestFinishedUnwound() {
218 TearDownTest();
219 test_finished_event_->Signal();
222 void PushNextTask(const base::Closure& task) {
223 task_stack_.push(task);
226 void ScheduleNextTask() {
227 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
228 if (task_stack_.empty()) {
229 TestFinished();
230 return;
232 base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
233 task_stack_.pop();
236 // MainResource_Miss --------------------------------------------------
238 void MainResource_Miss() {
239 PushNextTask(
240 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss,
241 base::Unretained(this)));
243 request_ = empty_context_.CreateRequest(
244 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
245 handler_.reset(host_->CreateRequestHandler(request_.get(),
246 RESOURCE_TYPE_MAIN_FRAME));
247 EXPECT_TRUE(handler_.get());
249 job_ = handler_->MaybeLoadResource(request_.get(),
250 request_->context()->network_delegate());
251 EXPECT_TRUE(job_.get());
252 EXPECT_TRUE(job_->is_waiting());
254 // We have to wait for completion of storage->FindResponseForMainRequest.
255 ScheduleNextTask();
258 void Verify_MainResource_Miss() {
259 EXPECT_FALSE(job_->is_waiting());
260 EXPECT_TRUE(job_->is_delivering_network_response());
262 int64 cache_id = kAppCacheNoCacheId;
263 GURL manifest_url;
264 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
265 EXPECT_EQ(kAppCacheNoCacheId, cache_id);
266 EXPECT_EQ(GURL(), manifest_url);
267 EXPECT_EQ(0, handler_->found_group_id_);
269 AppCacheURLRequestJob* fallback_job;
270 fallback_job = handler_->MaybeLoadFallbackForRedirect(
271 request_.get(),
272 request_->context()->network_delegate(),
273 GURL("http://blah/redirect"));
274 EXPECT_FALSE(fallback_job);
275 fallback_job = handler_->MaybeLoadFallbackForResponse(
276 request_.get(), request_->context()->network_delegate());
277 EXPECT_FALSE(fallback_job);
279 EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
281 TestFinished();
284 // MainResource_Hit --------------------------------------------------
286 void MainResource_Hit() {
287 PushNextTask(
288 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit,
289 base::Unretained(this)));
291 request_ = empty_context_.CreateRequest(
292 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
293 handler_.reset(host_->CreateRequestHandler(request_.get(),
294 RESOURCE_TYPE_MAIN_FRAME));
295 EXPECT_TRUE(handler_.get());
297 mock_storage()->SimulateFindMainResource(
298 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
299 GURL(), AppCacheEntry(),
300 1, 2, GURL("http://blah/manifest/"));
302 job_ = handler_->MaybeLoadResource(request_.get(),
303 request_->context()->network_delegate());
304 EXPECT_TRUE(job_.get());
305 EXPECT_TRUE(job_->is_waiting());
307 // We have to wait for completion of storage->FindResponseForMainRequest.
308 ScheduleNextTask();
311 void Verify_MainResource_Hit() {
312 EXPECT_FALSE(job_->is_waiting());
313 EXPECT_TRUE(job_->is_delivering_appcache_response());
315 int64 cache_id = kAppCacheNoCacheId;
316 GURL manifest_url;
317 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
318 EXPECT_EQ(1, cache_id);
319 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
320 EXPECT_EQ(2, handler_->found_group_id_);
322 AppCacheURLRequestJob* fallback_job;
323 fallback_job = handler_->MaybeLoadFallbackForResponse(
324 request_.get(), request_->context()->network_delegate());
325 EXPECT_FALSE(fallback_job);
327 EXPECT_EQ(GURL("http://blah/manifest/"),
328 host_->preferred_manifest_url());
330 TestFinished();
333 // MainResource_Fallback --------------------------------------------------
335 void MainResource_Fallback() {
336 PushNextTask(
337 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback,
338 base::Unretained(this)));
340 request_ = empty_context_.CreateRequest(
341 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
342 handler_.reset(host_->CreateRequestHandler(request_.get(),
343 RESOURCE_TYPE_MAIN_FRAME));
344 EXPECT_TRUE(handler_.get());
346 mock_storage()->SimulateFindMainResource(
347 AppCacheEntry(),
348 GURL("http://blah/fallbackurl"),
349 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
350 1, 2, GURL("http://blah/manifest/"));
352 job_ = handler_->MaybeLoadResource(request_.get(),
353 request_->context()->network_delegate());
354 EXPECT_TRUE(job_.get());
355 EXPECT_TRUE(job_->is_waiting());
357 // We have to wait for completion of storage->FindResponseForMainRequest.
358 ScheduleNextTask();
361 void SimulateResponseCode(int response_code) {
362 job_factory_->SetJob(
363 new MockURLRequestJob(
364 request_.get(),
365 request_->context()->network_delegate(),
366 response_code));
367 request_->Start();
368 // All our simulation needs to satisfy are the following two DCHECKs
369 DCHECK(request_->status().is_success());
370 DCHECK_EQ(response_code, request_->GetResponseCode());
373 void SimulateResponseInfo(const net::HttpResponseInfo& info) {
374 job_factory_->SetJob(
375 new MockURLRequestJob(
376 request_.get(),
377 request_->context()->network_delegate(), info));
378 request_->Start();
381 void Verify_MainResource_Fallback() {
382 EXPECT_FALSE(job_->is_waiting());
383 EXPECT_TRUE(job_->is_delivering_network_response());
385 // When the request is restarted, the existing job is dropped so a
386 // real network job gets created. We expect NULL here which will cause
387 // the net library to create a real job.
388 job_ = handler_->MaybeLoadResource(request_.get(),
389 request_->context()->network_delegate());
390 EXPECT_FALSE(job_.get());
392 // Simulate an http error of the real network job.
393 SimulateResponseCode(500);
395 job_ = handler_->MaybeLoadFallbackForResponse(
396 request_.get(), request_->context()->network_delegate());
397 EXPECT_TRUE(job_.get());
398 EXPECT_TRUE(job_->is_delivering_appcache_response());
400 int64 cache_id = kAppCacheNoCacheId;
401 GURL manifest_url;
402 handler_->GetExtraResponseInfo(&cache_id, &manifest_url);
403 EXPECT_EQ(1, cache_id);
404 EXPECT_EQ(GURL("http://blah/manifest/"), manifest_url);
405 EXPECT_TRUE(host_->main_resource_was_namespace_entry_);
406 EXPECT_EQ(GURL("http://blah/fallbackurl"), host_->namespace_entry_url_);
408 EXPECT_EQ(GURL("http://blah/manifest/"),
409 host_->preferred_manifest_url());
411 TestFinished();
414 // MainResource_FallbackOverride --------------------------------------------
416 void MainResource_FallbackOverride() {
417 PushNextTask(base::Bind(
418 &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride,
419 base::Unretained(this)));
421 request_ = empty_context_.CreateRequest(
422 GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY,
423 &delegate_, NULL);
424 handler_.reset(host_->CreateRequestHandler(request_.get(),
425 RESOURCE_TYPE_MAIN_FRAME));
426 EXPECT_TRUE(handler_.get());
428 mock_storage()->SimulateFindMainResource(
429 AppCacheEntry(),
430 GURL("http://blah/fallbackurl"),
431 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
432 1, 2, GURL("http://blah/manifest/"));
434 job_ = handler_->MaybeLoadResource(request_.get(),
435 request_->context()->network_delegate());
436 EXPECT_TRUE(job_.get());
437 EXPECT_TRUE(job_->is_waiting());
439 // We have to wait for completion of storage->FindResponseForMainRequest.
440 ScheduleNextTask();
443 void Verify_MainResource_FallbackOverride() {
444 EXPECT_FALSE(job_->is_waiting());
445 EXPECT_TRUE(job_->is_delivering_network_response());
447 // When the request is restarted, the existing job is dropped so a
448 // real network job gets created. We expect NULL here which will cause
449 // the net library to create a real job.
450 job_ = handler_->MaybeLoadResource(request_.get(),
451 request_->context()->network_delegate());
452 EXPECT_FALSE(job_.get());
454 // Simulate an http error of the real network job, but with custom
455 // headers that override the fallback behavior.
456 const char kOverrideHeaders[] =
457 "HTTP/1.1 404 BOO HOO\0"
458 "x-chromium-appcache-fallback-override: disallow-fallback\0"
459 "\0";
460 net::HttpResponseInfo info;
461 info.headers = new net::HttpResponseHeaders(
462 std::string(kOverrideHeaders, arraysize(kOverrideHeaders)));
463 SimulateResponseInfo(info);
465 job_ = handler_->MaybeLoadFallbackForResponse(
466 request_.get(), request_->context()->network_delegate());
467 EXPECT_FALSE(job_.get());
469 TestFinished();
472 // SubResource_Miss_WithNoCacheSelected ----------------------------------
474 void SubResource_Miss_WithNoCacheSelected() {
475 request_ = empty_context_.CreateRequest(
476 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
477 handler_.reset(host_->CreateRequestHandler(request_.get(),
478 RESOURCE_TYPE_SUB_RESOURCE));
480 // We avoid creating handler when possible, sub-resource requests are not
481 // subject to retrieval from an appcache when there's no associated cache.
482 EXPECT_FALSE(handler_.get());
484 TestFinished();
487 // SubResource_Miss_WithCacheSelected ----------------------------------
489 void SubResource_Miss_WithCacheSelected() {
490 // A sub-resource load where the resource is not in an appcache, or
491 // in a network or fallback namespace, should result in a failed request.
492 host_->AssociateCompleteCache(MakeNewCache());
494 request_ = empty_context_.CreateRequest(
495 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
496 handler_.reset(host_->CreateRequestHandler(request_.get(),
497 RESOURCE_TYPE_SUB_RESOURCE));
498 EXPECT_TRUE(handler_.get());
500 job_ = handler_->MaybeLoadResource(request_.get(),
501 request_->context()->network_delegate());
502 EXPECT_TRUE(job_.get());
503 EXPECT_TRUE(job_->is_delivering_error_response());
505 AppCacheURLRequestJob* fallback_job;
506 fallback_job = handler_->MaybeLoadFallbackForRedirect(
507 request_.get(),
508 request_->context()->network_delegate(),
509 GURL("http://blah/redirect"));
510 EXPECT_FALSE(fallback_job);
511 fallback_job = handler_->MaybeLoadFallbackForResponse(
512 request_.get(), request_->context()->network_delegate());
513 EXPECT_FALSE(fallback_job);
515 TestFinished();
518 // SubResource_Miss_WithWaitForCacheSelection -----------------------------
520 void SubResource_Miss_WithWaitForCacheSelection() {
521 // Precondition, the host is waiting on cache selection.
522 scoped_refptr<AppCache> cache(MakeNewCache());
523 host_->pending_selected_cache_id_ = cache->cache_id();
524 host_->set_preferred_manifest_url(cache->owning_group()->manifest_url());
526 request_ = empty_context_.CreateRequest(
527 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
528 handler_.reset(host_->CreateRequestHandler(request_.get(),
529 RESOURCE_TYPE_SUB_RESOURCE));
530 EXPECT_TRUE(handler_.get());
531 job_ = handler_->MaybeLoadResource(request_.get(),
532 request_->context()->network_delegate());
533 EXPECT_TRUE(job_.get());
534 EXPECT_TRUE(job_->is_waiting());
536 host_->FinishCacheSelection(cache.get(), NULL);
537 EXPECT_FALSE(job_->is_waiting());
538 EXPECT_TRUE(job_->is_delivering_error_response());
540 AppCacheURLRequestJob* fallback_job;
541 fallback_job = handler_->MaybeLoadFallbackForRedirect(
542 request_.get(),
543 request_->context()->network_delegate(),
544 GURL("http://blah/redirect"));
545 EXPECT_FALSE(fallback_job);
546 fallback_job = handler_->MaybeLoadFallbackForResponse(
547 request_.get(), request_->context()->network_delegate());
548 EXPECT_FALSE(fallback_job);
550 TestFinished();
553 // SubResource_Hit -----------------------------
555 void SubResource_Hit() {
556 host_->AssociateCompleteCache(MakeNewCache());
558 mock_storage()->SimulateFindSubResource(
559 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
561 request_ = empty_context_.CreateRequest(
562 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
563 handler_.reset(host_->CreateRequestHandler(request_.get(),
564 RESOURCE_TYPE_SUB_RESOURCE));
565 EXPECT_TRUE(handler_.get());
566 job_ = handler_->MaybeLoadResource(request_.get(),
567 request_->context()->network_delegate());
568 EXPECT_TRUE(job_.get());
569 EXPECT_TRUE(job_->is_delivering_appcache_response());
571 AppCacheURLRequestJob* fallback_job;
572 fallback_job = handler_->MaybeLoadFallbackForRedirect(
573 request_.get(),
574 request_->context()->network_delegate(),
575 GURL("http://blah/redirect"));
576 EXPECT_FALSE(fallback_job);
577 fallback_job = handler_->MaybeLoadFallbackForResponse(
578 request_.get(), request_->context()->network_delegate());
579 EXPECT_FALSE(fallback_job);
581 TestFinished();
584 // SubResource_RedirectFallback -----------------------------
586 void SubResource_RedirectFallback() {
587 // Redirects to resources in the a different origin are subject to
588 // fallback namespaces.
589 host_->AssociateCompleteCache(MakeNewCache());
591 mock_storage()->SimulateFindSubResource(
592 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
594 request_ = empty_context_.CreateRequest(
595 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
596 handler_.reset(host_->CreateRequestHandler(request_.get(),
597 RESOURCE_TYPE_SUB_RESOURCE));
598 EXPECT_TRUE(handler_.get());
599 job_ = handler_->MaybeLoadResource(request_.get(),
600 request_->context()->network_delegate());
601 EXPECT_FALSE(job_.get());
603 job_ = handler_->MaybeLoadFallbackForRedirect(
604 request_.get(),
605 request_->context()->network_delegate(),
606 GURL("http://not_blah/redirect"));
607 EXPECT_TRUE(job_.get());
608 EXPECT_TRUE(job_->is_delivering_appcache_response());
610 AppCacheURLRequestJob* fallback_job;
611 fallback_job = handler_->MaybeLoadFallbackForResponse(
612 request_.get(), request_->context()->network_delegate());
613 EXPECT_FALSE(fallback_job);
615 TestFinished();
618 // SubResource_NoRedirectFallback -----------------------------
620 void SubResource_NoRedirectFallback() {
621 // Redirects to resources in the same-origin are not subject to
622 // fallback namespaces.
623 host_->AssociateCompleteCache(MakeNewCache());
625 mock_storage()->SimulateFindSubResource(
626 AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
628 request_ = empty_context_.CreateRequest(
629 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
630 handler_.reset(host_->CreateRequestHandler(request_.get(),
631 RESOURCE_TYPE_SUB_RESOURCE));
632 EXPECT_TRUE(handler_.get());
633 job_ = handler_->MaybeLoadResource(request_.get(),
634 request_->context()->network_delegate());
635 EXPECT_FALSE(job_.get());
637 AppCacheURLRequestJob* fallback_job;
638 fallback_job = handler_->MaybeLoadFallbackForRedirect(
639 request_.get(),
640 request_->context()->network_delegate(),
641 GURL("http://blah/redirect"));
642 EXPECT_FALSE(fallback_job);
644 SimulateResponseCode(200);
645 fallback_job = handler_->MaybeLoadFallbackForResponse(
646 request_.get(), request_->context()->network_delegate());
647 EXPECT_FALSE(fallback_job);
649 TestFinished();
652 // SubResource_Network -----------------------------
654 void SubResource_Network() {
655 // A sub-resource load where the resource is in a network namespace,
656 // should result in the system using a 'real' job to do the network
657 // retrieval.
658 host_->AssociateCompleteCache(MakeNewCache());
660 mock_storage()->SimulateFindSubResource(
661 AppCacheEntry(), AppCacheEntry(), true);
663 request_ = empty_context_.CreateRequest(
664 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
665 handler_.reset(host_->CreateRequestHandler(request_.get(),
666 RESOURCE_TYPE_SUB_RESOURCE));
667 EXPECT_TRUE(handler_.get());
668 job_ = handler_->MaybeLoadResource(request_.get(),
669 request_->context()->network_delegate());
670 EXPECT_FALSE(job_.get());
672 AppCacheURLRequestJob* fallback_job;
673 fallback_job = handler_->MaybeLoadFallbackForRedirect(
674 request_.get(),
675 request_->context()->network_delegate(),
676 GURL("http://blah/redirect"));
677 EXPECT_FALSE(fallback_job);
678 fallback_job = handler_->MaybeLoadFallbackForResponse(
679 request_.get(), request_->context()->network_delegate());
680 EXPECT_FALSE(fallback_job);
682 TestFinished();
685 // DestroyedHost -----------------------------
687 void DestroyedHost() {
688 host_->AssociateCompleteCache(MakeNewCache());
690 mock_storage()->SimulateFindSubResource(
691 AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
693 request_ = empty_context_.CreateRequest(
694 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
695 handler_.reset(host_->CreateRequestHandler(request_.get(),
696 RESOURCE_TYPE_SUB_RESOURCE));
697 EXPECT_TRUE(handler_.get());
699 backend_impl_->UnregisterHost(1);
700 host_ = NULL;
702 EXPECT_FALSE(handler_->MaybeLoadResource(
703 request_.get(), request_->context()->network_delegate()));
704 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
705 request_.get(),
706 request_->context()->network_delegate(),
707 GURL("http://blah/redirect")));
708 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
709 request_.get(), request_->context()->network_delegate()));
711 TestFinished();
714 // DestroyedHostWithWaitingJob -----------------------------
716 void DestroyedHostWithWaitingJob() {
717 // Precondition, the host is waiting on cache selection.
718 host_->pending_selected_cache_id_ = 1;
720 request_ = empty_context_.CreateRequest(
721 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
722 handler_.reset(host_->CreateRequestHandler(request_.get(),
723 RESOURCE_TYPE_SUB_RESOURCE));
724 EXPECT_TRUE(handler_.get());
726 job_ = handler_->MaybeLoadResource(request_.get(),
727 request_->context()->network_delegate());
728 EXPECT_TRUE(job_.get());
729 EXPECT_TRUE(job_->is_waiting());
731 backend_impl_->UnregisterHost(1);
732 host_ = NULL;
733 EXPECT_TRUE(job_->has_been_killed());
735 EXPECT_FALSE(handler_->MaybeLoadResource(
736 request_.get(), request_->context()->network_delegate()));
737 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
738 request_.get(),
739 request_->context()->network_delegate(),
740 GURL("http://blah/redirect")));
741 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
742 request_.get(), request_->context()->network_delegate()));
744 TestFinished();
747 // UnsupportedScheme -----------------------------
749 void UnsupportedScheme() {
750 // Precondition, the host is waiting on cache selection.
751 host_->pending_selected_cache_id_ = 1;
753 request_ = empty_context_.CreateRequest(
754 GURL("ftp://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
755 handler_.reset(host_->CreateRequestHandler(request_.get(),
756 RESOURCE_TYPE_SUB_RESOURCE));
757 EXPECT_TRUE(handler_.get()); // we could redirect to http (conceivably)
759 EXPECT_FALSE(handler_->MaybeLoadResource(
760 request_.get(), request_->context()->network_delegate()));
761 EXPECT_FALSE(handler_->MaybeLoadFallbackForRedirect(
762 request_.get(),
763 request_->context()->network_delegate(),
764 GURL("ftp://blah/redirect")));
765 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
766 request_.get(), request_->context()->network_delegate()));
768 TestFinished();
771 // CanceledRequest -----------------------------
773 void CanceledRequest() {
774 request_ = empty_context_.CreateRequest(
775 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
776 handler_.reset(host_->CreateRequestHandler(request_.get(),
777 RESOURCE_TYPE_MAIN_FRAME));
778 EXPECT_TRUE(handler_.get());
780 job_ = handler_->MaybeLoadResource(request_.get(),
781 request_->context()->network_delegate());
782 EXPECT_TRUE(job_.get());
783 EXPECT_TRUE(job_->is_waiting());
784 EXPECT_FALSE(job_->has_been_started());
786 job_factory_->SetJob(job_.get());
787 request_->Start();
788 EXPECT_TRUE(job_->has_been_started());
790 request_->Cancel();
791 EXPECT_TRUE(job_->has_been_killed());
793 EXPECT_FALSE(handler_->MaybeLoadFallbackForResponse(
794 request_.get(), request_->context()->network_delegate()));
796 TestFinished();
799 // WorkerRequest -----------------------------
801 void WorkerRequest() {
802 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
803 RESOURCE_TYPE_MAIN_FRAME));
804 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
805 RESOURCE_TYPE_SUB_FRAME));
806 EXPECT_TRUE(AppCacheRequestHandler::IsMainResourceType(
807 RESOURCE_TYPE_SHARED_WORKER));
808 EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
809 RESOURCE_TYPE_WORKER));
811 request_ = empty_context_.CreateRequest(
812 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
814 const int kParentHostId = host_->host_id();
815 const int kWorkerHostId = 2;
816 const int kAbandonedWorkerHostId = 3;
817 const int kNonExsitingHostId = 700;
819 backend_impl_->RegisterHost(kWorkerHostId);
820 AppCacheHost* worker_host = backend_impl_->GetHost(kWorkerHostId);
821 worker_host->SelectCacheForWorker(kParentHostId, kMockProcessId);
822 handler_.reset(worker_host->CreateRequestHandler(
823 request_.get(), RESOURCE_TYPE_SHARED_WORKER));
824 EXPECT_TRUE(handler_.get());
825 // Verify that the handler is associated with the parent host.
826 EXPECT_EQ(host_, handler_->host_);
828 // Create a new worker host, but associate it with a parent host that
829 // does not exists to simulate the host having been torn down.
830 backend_impl_->UnregisterHost(kWorkerHostId);
831 backend_impl_->RegisterHost(kAbandonedWorkerHostId);
832 worker_host = backend_impl_->GetHost(kAbandonedWorkerHostId);
833 EXPECT_EQ(NULL, backend_impl_->GetHost(kNonExsitingHostId));
834 worker_host->SelectCacheForWorker(kNonExsitingHostId, kMockProcessId);
835 handler_.reset(worker_host->CreateRequestHandler(
836 request_.get(), RESOURCE_TYPE_SHARED_WORKER));
837 EXPECT_FALSE(handler_.get());
839 TestFinished();
842 // MainResource_Blocked --------------------------------------------------
844 void MainResource_Blocked() {
845 PushNextTask(
846 base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked,
847 base::Unretained(this)));
849 request_ = empty_context_.CreateRequest(
850 GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_, NULL);
851 handler_.reset(host_->CreateRequestHandler(request_.get(),
852 RESOURCE_TYPE_MAIN_FRAME));
853 EXPECT_TRUE(handler_.get());
855 mock_policy_->can_load_return_value_ = false;
856 mock_storage()->SimulateFindMainResource(
857 AppCacheEntry(AppCacheEntry::EXPLICIT, 1),
858 GURL(), AppCacheEntry(),
859 1, 2, GURL("http://blah/manifest/"));
861 job_ = handler_->MaybeLoadResource(request_.get(),
862 request_->context()->network_delegate());
863 EXPECT_TRUE(job_.get());
864 EXPECT_TRUE(job_->is_waiting());
866 // We have to wait for completion of storage->FindResponseForMainRequest.
867 ScheduleNextTask();
870 void Verify_MainResource_Blocked() {
871 EXPECT_FALSE(job_->is_waiting());
872 EXPECT_FALSE(job_->is_delivering_appcache_response());
874 EXPECT_EQ(0, handler_->found_cache_id_);
875 EXPECT_EQ(0, handler_->found_group_id_);
876 EXPECT_TRUE(handler_->found_manifest_url_.is_empty());
877 EXPECT_TRUE(host_->preferred_manifest_url().is_empty());
878 EXPECT_TRUE(host_->main_resource_blocked_);
879 EXPECT_TRUE(host_->blocked_manifest_url_ == GURL("http://blah/manifest/"));
881 TestFinished();
884 // Test case helpers --------------------------------------------------
886 AppCache* MakeNewCache() {
887 AppCache* cache = new AppCache(
888 mock_storage(), mock_storage()->NewCacheId());
889 cache->set_complete(true);
890 AppCacheGroup* group = new AppCacheGroup(
891 mock_storage(), GURL("http://blah/manifest"),
892 mock_storage()->NewGroupId());
893 group->AddCache(cache);
894 return cache;
897 MockAppCacheStorage* mock_storage() {
898 return reinterpret_cast<MockAppCacheStorage*>(mock_service_->storage());
901 // Data members --------------------------------------------------
903 scoped_ptr<base::WaitableEvent> test_finished_event_;
904 std::stack<base::Closure> task_stack_;
905 scoped_ptr<MockAppCacheService> mock_service_;
906 scoped_ptr<AppCacheBackendImpl> backend_impl_;
907 scoped_ptr<MockFrontend> mock_frontend_;
908 scoped_ptr<MockAppCachePolicy> mock_policy_;
909 AppCacheHost* host_;
910 net::URLRequestContext empty_context_;
911 scoped_ptr<MockURLRequestJobFactory> job_factory_;
912 MockURLRequestDelegate delegate_;
913 scoped_ptr<net::URLRequest> request_;
914 scoped_ptr<AppCacheRequestHandler> handler_;
915 scoped_refptr<AppCacheURLRequestJob> job_;
917 static scoped_ptr<base::Thread> io_thread_;
920 // static
921 scoped_ptr<base::Thread> AppCacheRequestHandlerTest::io_thread_;
923 TEST_F(AppCacheRequestHandlerTest, MainResource_Miss) {
924 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Miss);
927 TEST_F(AppCacheRequestHandlerTest, MainResource_Hit) {
928 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Hit);
931 TEST_F(AppCacheRequestHandlerTest, MainResource_Fallback) {
932 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Fallback);
935 TEST_F(AppCacheRequestHandlerTest, MainResource_FallbackOverride) {
936 RunTestOnIOThread(
937 &AppCacheRequestHandlerTest::MainResource_FallbackOverride);
940 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithNoCacheSelected) {
941 RunTestOnIOThread(
942 &AppCacheRequestHandlerTest::SubResource_Miss_WithNoCacheSelected);
945 TEST_F(AppCacheRequestHandlerTest, SubResource_Miss_WithCacheSelected) {
946 RunTestOnIOThread(
947 &AppCacheRequestHandlerTest::SubResource_Miss_WithCacheSelected);
950 TEST_F(AppCacheRequestHandlerTest,
951 SubResource_Miss_WithWaitForCacheSelection) {
952 RunTestOnIOThread(
953 &AppCacheRequestHandlerTest::SubResource_Miss_WithWaitForCacheSelection);
956 TEST_F(AppCacheRequestHandlerTest, SubResource_Hit) {
957 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Hit);
960 TEST_F(AppCacheRequestHandlerTest, SubResource_RedirectFallback) {
961 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_RedirectFallback);
964 TEST_F(AppCacheRequestHandlerTest, SubResource_NoRedirectFallback) {
965 RunTestOnIOThread(
966 &AppCacheRequestHandlerTest::SubResource_NoRedirectFallback);
969 TEST_F(AppCacheRequestHandlerTest, SubResource_Network) {
970 RunTestOnIOThread(&AppCacheRequestHandlerTest::SubResource_Network);
973 TEST_F(AppCacheRequestHandlerTest, DestroyedHost) {
974 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHost);
977 TEST_F(AppCacheRequestHandlerTest, DestroyedHostWithWaitingJob) {
978 RunTestOnIOThread(&AppCacheRequestHandlerTest::DestroyedHostWithWaitingJob);
981 TEST_F(AppCacheRequestHandlerTest, UnsupportedScheme) {
982 RunTestOnIOThread(&AppCacheRequestHandlerTest::UnsupportedScheme);
985 TEST_F(AppCacheRequestHandlerTest, CanceledRequest) {
986 RunTestOnIOThread(&AppCacheRequestHandlerTest::CanceledRequest);
989 TEST_F(AppCacheRequestHandlerTest, WorkerRequest) {
990 RunTestOnIOThread(&AppCacheRequestHandlerTest::WorkerRequest);
993 TEST_F(AppCacheRequestHandlerTest, MainResource_Blocked) {
994 RunTestOnIOThread(&AppCacheRequestHandlerTest::MainResource_Blocked);
997 } // namespace content