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.
9 #include "base/bind_helpers.h"
10 #include "base/callback.h"
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/pickle.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/threading/thread.h"
17 #include "content/browser/appcache/appcache_response.h"
18 #include "content/browser/appcache/appcache_url_request_job.h"
19 #include "content/browser/appcache/mock_appcache_service.h"
20 #include "net/base/io_buffer.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"
32 using net::WrappedIOBuffer
;
38 const char kHttpBasicHeaders
[] = "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
39 const char kHttpBasicBody
[] = "Hello";
41 const int kNumBlocks
= 4;
42 const int kBlockSize
= 1024;
44 class MockURLRequestJobFactory
: public net::URLRequestJobFactory
{
46 MockURLRequestJobFactory() : job_(NULL
) {
49 virtual ~MockURLRequestJobFactory() {
53 void SetJob(net::URLRequestJob
* job
) {
57 bool has_job() const {
61 // net::URLRequestJobFactory implementation.
62 virtual net::URLRequestJob
* MaybeCreateJobWithProtocolHandler(
63 const std::string
& scheme
,
64 net::URLRequest
* request
,
65 net::NetworkDelegate
* network_delegate
) const OVERRIDE
{
67 net::URLRequestJob
* temp
= job_
;
71 return new net::URLRequestErrorJob(request
,
73 net::ERR_INTERNET_DISCONNECTED
);
77 virtual bool IsHandledProtocol(const std::string
& scheme
) const OVERRIDE
{
78 return scheme
== "http";
81 virtual bool IsHandledURL(const GURL
& url
) const OVERRIDE
{
82 return url
.SchemeIs("http");
85 virtual bool IsSafeRedirectTarget(const GURL
& location
) const OVERRIDE
{
90 mutable net::URLRequestJob
* job_
;
93 class AppCacheURLRequestJobTest
: public testing::Test
{
96 // Test Harness -------------------------------------------------------------
97 // TODO(michaeln): share this test harness with AppCacheResponseTest
99 class MockStorageDelegate
: public AppCacheStorage::Delegate
{
101 explicit MockStorageDelegate(AppCacheURLRequestJobTest
* test
)
102 : loaded_info_id_(0), test_(test
) {
105 virtual void OnResponseInfoLoaded(AppCacheResponseInfo
* info
,
106 int64 response_id
) OVERRIDE
{
108 loaded_info_id_
= response_id
;
109 test_
->ScheduleNextTask();
112 scoped_refptr
<AppCacheResponseInfo
> loaded_info_
;
113 int64 loaded_info_id_
;
114 AppCacheURLRequestJobTest
* test_
;
117 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
119 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest
* test
)
121 received_data_(new net::IOBuffer(kNumBlocks
* kBlockSize
)),
122 did_receive_headers_(false), amount_received_(0),
123 kill_after_amount_received_(0), kill_with_io_pending_(false) {
126 virtual void OnResponseStarted(net::URLRequest
* request
) OVERRIDE
{
127 amount_received_
= 0;
128 did_receive_headers_
= false;
129 if (request
->status().is_success()) {
130 EXPECT_TRUE(request
->response_headers());
131 did_receive_headers_
= true;
132 received_info_
= request
->response_info();
139 virtual void OnReadCompleted(net::URLRequest
* request
,
140 int bytes_read
) OVERRIDE
{
141 if (bytes_read
> 0) {
142 amount_received_
+= bytes_read
;
144 if (kill_after_amount_received_
&& !kill_with_io_pending_
) {
145 if (amount_received_
>= kill_after_amount_received_
) {
153 if (kill_after_amount_received_
&& kill_with_io_pending_
) {
154 if (amount_received_
>= kill_after_amount_received_
) {
164 void ReadSome(net::URLRequest
* request
) {
165 DCHECK(amount_received_
+ kBlockSize
<= kNumBlocks
* kBlockSize
);
166 scoped_refptr
<IOBuffer
> wrapped_buffer(
167 new net::WrappedIOBuffer(received_data_
->data() + amount_received_
));
170 request
->Read(wrapped_buffer
.get(), kBlockSize
, &bytes_read
));
171 EXPECT_EQ(0, bytes_read
);
174 void RequestComplete() {
175 test_
->ScheduleNextTask();
178 AppCacheURLRequestJobTest
* test_
;
179 net::HttpResponseInfo received_info_
;
180 scoped_refptr
<net::IOBuffer
> received_data_
;
181 bool did_receive_headers_
;
182 int amount_received_
;
183 int kill_after_amount_received_
;
184 bool kill_with_io_pending_
;
187 // Helper callback to run a test on our io_thread. The io_thread is spun up
188 // once and reused for all tests.
189 template <class Method
>
190 void MethodWrapper(Method method
) {
195 static void SetUpTestCase() {
196 io_thread_
.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
197 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
198 io_thread_
->StartWithOptions(options
);
201 static void TearDownTestCase() {
202 io_thread_
.reset(NULL
);
205 AppCacheURLRequestJobTest() {}
207 template <class Method
>
208 void RunTestOnIOThread(Method method
) {
209 test_finished_event_
.reset(new base::WaitableEvent(false, false));
210 io_thread_
->message_loop()->PostTask(
211 FROM_HERE
, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper
<Method
>,
212 base::Unretained(this), method
));
213 test_finished_event_
->Wait();
217 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
218 DCHECK(task_stack_
.empty());
220 storage_delegate_
.reset(new MockStorageDelegate(this));
221 service_
.reset(new MockAppCacheService());
222 expected_read_result_
= 0;
223 expected_write_result_
= 0;
224 written_response_id_
= 0;
225 reader_deletion_count_down_
= 0;
226 writer_deletion_count_down_
= 0;
228 url_request_delegate_
.reset(new MockURLRequestDelegate(this));
229 job_factory_
.reset(new MockURLRequestJobFactory());
230 empty_context_
.reset(new net::URLRequestContext());
231 empty_context_
->set_job_factory(job_factory_
.get());
234 void TearDownTest() {
235 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
238 while (!task_stack_
.empty())
243 read_info_buffer_
= NULL
;
245 write_buffer_
= NULL
;
246 write_info_buffer_
= NULL
;
247 storage_delegate_
.reset();
250 DCHECK(!job_factory_
->has_job());
251 empty_context_
.reset();
252 job_factory_
.reset();
253 url_request_delegate_
.reset();
256 void TestFinished() {
257 // We unwind the stack prior to finishing up to let stack
258 // based objects get deleted.
259 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
260 base::MessageLoop::current()->PostTask(
262 base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound
,
263 base::Unretained(this)));
266 void TestFinishedUnwound() {
268 test_finished_event_
->Signal();
271 void PushNextTask(const base::Closure
& task
) {
272 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, false));
275 void PushNextTaskAsImmediate(const base::Closure
& task
) {
276 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, true));
279 void ScheduleNextTask() {
280 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
281 if (task_stack_
.empty()) {
285 base::Closure task
=task_stack_
.top().first
;
286 bool immediate
= task_stack_
.top().second
;
291 base::MessageLoop::current()->PostTask(FROM_HERE
, task
);
294 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
296 void WriteBasicResponse() {
297 scoped_refptr
<IOBuffer
> body(new WrappedIOBuffer(kHttpBasicBody
));
298 std::string
raw_headers(kHttpBasicHeaders
, arraysize(kHttpBasicHeaders
));
300 MakeHttpResponseInfo(raw_headers
), body
.get(), strlen(kHttpBasicBody
));
303 void WriteResponse(net::HttpResponseInfo
* head
,
304 IOBuffer
* body
, int body_len
) {
306 scoped_refptr
<IOBuffer
> body_ref(body
);
307 PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody
,
308 base::Unretained(this), body_ref
, body_len
));
309 WriteResponseHead(head
);
312 void WriteResponseHead(net::HttpResponseInfo
* head
) {
313 EXPECT_FALSE(writer_
->IsWritePending());
314 expected_write_result_
= GetHttpResponseInfoSize(head
);
315 write_info_buffer_
= new HttpResponseInfoIOBuffer(head
);
317 write_info_buffer_
.get(),
318 base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete
,
319 base::Unretained(this)));
322 void WriteResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
323 EXPECT_FALSE(writer_
->IsWritePending());
324 write_buffer_
= io_buffer
;
325 expected_write_result_
= buf_len
;
326 writer_
->WriteData(write_buffer_
.get(),
328 base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete
,
329 base::Unretained(this)));
332 void ReadResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
333 EXPECT_FALSE(reader_
->IsReadPending());
334 read_buffer_
= io_buffer
;
335 expected_read_result_
= buf_len
;
336 reader_
->ReadData(read_buffer_
.get(),
338 base::Bind(&AppCacheURLRequestJobTest::OnReadComplete
,
339 base::Unretained(this)));
342 // AppCacheResponseReader / Writer completion callbacks
344 void OnWriteInfoComplete(int result
) {
345 EXPECT_FALSE(writer_
->IsWritePending());
346 EXPECT_EQ(expected_write_result_
, result
);
350 void OnWriteComplete(int result
) {
351 EXPECT_FALSE(writer_
->IsWritePending());
352 EXPECT_EQ(expected_write_result_
, result
);
356 void OnReadInfoComplete(int result
) {
357 EXPECT_FALSE(reader_
->IsReadPending());
358 EXPECT_EQ(expected_read_result_
, result
);
362 void OnReadComplete(int result
) {
363 EXPECT_FALSE(reader_
->IsReadPending());
364 EXPECT_EQ(expected_read_result_
, result
);
368 // Helpers to work with HttpResponseInfo objects
370 net::HttpResponseInfo
* MakeHttpResponseInfo(const std::string
& raw_headers
) {
371 net::HttpResponseInfo
* info
= new net::HttpResponseInfo
;
372 info
->request_time
= base::Time::Now();
373 info
->response_time
= base::Time::Now();
374 info
->was_cached
= false;
375 info
->headers
= new net::HttpResponseHeaders(raw_headers
);
379 int GetHttpResponseInfoSize(const net::HttpResponseInfo
* info
) {
381 return PickleHttpResonseInfo(&pickle
, info
);
384 bool CompareHttpResponseInfos(const net::HttpResponseInfo
* info1
,
385 const net::HttpResponseInfo
* info2
) {
388 PickleHttpResonseInfo(&pickle1
, info1
);
389 PickleHttpResonseInfo(&pickle2
, info2
);
390 return (pickle1
.size() == pickle2
.size()) &&
391 (0 == memcmp(pickle1
.data(), pickle2
.data(), pickle1
.size()));
394 int PickleHttpResonseInfo(Pickle
* pickle
, const net::HttpResponseInfo
* info
) {
395 const bool kSkipTransientHeaders
= true;
396 const bool kTruncated
= false;
397 info
->Persist(pickle
, kSkipTransientHeaders
, kTruncated
);
398 return pickle
->size();
401 // Helpers to fill and verify blocks of memory with a value
403 void FillData(char value
, char* data
, int data_len
) {
404 memset(data
, value
, data_len
);
407 bool CheckData(char value
, const char* data
, int data_len
) {
408 for (int i
= 0; i
< data_len
; ++i
, ++data
) {
415 // Individual Tests ---------------------------------------------------------
416 // Some of the individual tests involve multiple async steps. Each test
417 // is delineated with a section header.
419 // Basic -------------------------------------------------------------------
421 AppCacheStorage
* storage
= service_
->storage();
422 scoped_ptr
<net::URLRequest
> request(empty_context_
->CreateRequest(
423 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
, NULL
));
424 scoped_refptr
<AppCacheURLRequestJob
> job
;
426 // Create an instance and see that it looks as expected.
428 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
429 EXPECT_TRUE(job
->is_waiting());
430 EXPECT_FALSE(job
->is_delivering_appcache_response());
431 EXPECT_FALSE(job
->is_delivering_network_response());
432 EXPECT_FALSE(job
->is_delivering_error_response());
433 EXPECT_FALSE(job
->has_been_started());
434 EXPECT_FALSE(job
->has_been_killed());
435 EXPECT_EQ(GURL(), job
->manifest_url());
436 EXPECT_EQ(kAppCacheNoCacheId
, job
->cache_id());
437 EXPECT_FALSE(job
->entry().has_response_id());
442 // DeliveryOrders -----------------------------------------------------
443 void DeliveryOrders() {
444 AppCacheStorage
* storage
= service_
->storage();
445 scoped_ptr
<net::URLRequest
> request(empty_context_
->CreateRequest(
446 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
, NULL
));
447 scoped_refptr
<AppCacheURLRequestJob
> job
;
449 // Create an instance, give it a delivery order and see that
450 // it looks as expected.
452 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
453 job
->DeliverErrorResponse();
454 EXPECT_TRUE(job
->is_delivering_error_response());
455 EXPECT_FALSE(job
->has_been_started());
457 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
458 job
->DeliverNetworkResponse();
459 EXPECT_TRUE(job
->is_delivering_network_response());
460 EXPECT_FALSE(job
->has_been_started());
462 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
463 const GURL
kManifestUrl("http://blah/");
464 const int64
kCacheId(1);
465 const int64
kGroupId(1);
466 const AppCacheEntry
kEntry(AppCacheEntry::EXPLICIT
, 1);
467 job
->DeliverAppCachedResponse(kManifestUrl
, kCacheId
, kGroupId
,
469 EXPECT_FALSE(job
->is_waiting());
470 EXPECT_TRUE(job
->is_delivering_appcache_response());
471 EXPECT_FALSE(job
->has_been_started());
472 EXPECT_EQ(kManifestUrl
, job
->manifest_url());
473 EXPECT_EQ(kCacheId
, job
->cache_id());
474 EXPECT_EQ(kGroupId
, job
->group_id());
475 EXPECT_EQ(kEntry
.types(), job
->entry().types());
476 EXPECT_EQ(kEntry
.response_id(), job
->entry().response_id());
481 // DeliverNetworkResponse --------------------------------------------------
483 void DeliverNetworkResponse() {
484 // This test has async steps.
486 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse
,
487 base::Unretained(this)));
489 AppCacheStorage
* storage
= service_
->storage();
490 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
491 net::DEFAULT_PRIORITY
,
492 url_request_delegate_
.get(),
495 // Setup to create an AppCacheURLRequestJob with orders to deliver
496 // a network response.
497 AppCacheURLRequestJob
* mock_job
= new AppCacheURLRequestJob(
498 request_
.get(), NULL
, storage
, NULL
, false);
499 job_factory_
->SetJob(mock_job
);
500 mock_job
->DeliverNetworkResponse();
501 EXPECT_TRUE(mock_job
->is_delivering_network_response());
502 EXPECT_FALSE(mock_job
->has_been_started());
504 // Start the request.
507 // The job should have been picked up.
508 EXPECT_FALSE(job_factory_
->has_job());
509 // Completion is async.
512 void VerifyDeliverNetworkResponse() {
513 EXPECT_EQ(request_
->status().error(),
514 net::ERR_INTERNET_DISCONNECTED
);
518 // DeliverErrorResponse --------------------------------------------------
520 void DeliverErrorResponse() {
521 // This test has async steps.
523 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse
,
524 base::Unretained(this)));
526 AppCacheStorage
* storage
= service_
->storage();
527 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
528 net::DEFAULT_PRIORITY
,
529 url_request_delegate_
.get(),
532 // Setup to create an AppCacheURLRequestJob with orders to deliver
533 // a network response.
534 AppCacheURLRequestJob
* mock_job
= new AppCacheURLRequestJob(
535 request_
.get(), NULL
, storage
, NULL
, false);
536 job_factory_
->SetJob(mock_job
);
537 mock_job
->DeliverErrorResponse();
538 EXPECT_TRUE(mock_job
->is_delivering_error_response());
539 EXPECT_FALSE(mock_job
->has_been_started());
541 // Start the request.
544 // The job should have been picked up.
545 EXPECT_FALSE(job_factory_
->has_job());
546 // Completion is async.
549 void VerifyDeliverErrorResponse() {
550 EXPECT_EQ(request_
->status().error(), net::ERR_FAILED
);
554 // DeliverSmallAppCachedResponse --------------------------------------
555 // "Small" being small enough to read completely in a single
556 // request->Read call.
558 void DeliverSmallAppCachedResponse() {
559 // This test has several async steps.
560 // 1. Write a small response to response storage.
561 // 2. Use net::URLRequest to retrieve it.
562 // 3. Verify we received what we expected to receive.
564 PushNextTask(base::Bind(
565 &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse
,
566 base::Unretained(this)));
568 base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource
,
569 base::Unretained(this), false));
571 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
572 written_response_id_
= writer_
->response_id();
573 WriteBasicResponse();
577 void RequestAppCachedResource(bool start_after_delivery_orders
) {
578 AppCacheStorage
* storage
= service_
->storage();
579 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
580 net::DEFAULT_PRIORITY
,
581 url_request_delegate_
.get(),
584 // Setup to create an AppCacheURLRequestJob with orders to deliver
585 // a network response.
586 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
587 request_
.get(), NULL
, storage
, NULL
, false));
589 if (start_after_delivery_orders
) {
590 job
->DeliverAppCachedResponse(
592 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
594 EXPECT_TRUE(job
->is_delivering_appcache_response());
597 // Start the request.
598 EXPECT_FALSE(job
->has_been_started());
599 job_factory_
->SetJob(job
.get());
601 EXPECT_FALSE(job_factory_
->has_job());
602 EXPECT_TRUE(job
->has_been_started());
604 if (!start_after_delivery_orders
) {
605 job
->DeliverAppCachedResponse(
607 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
609 EXPECT_TRUE(job
->is_delivering_appcache_response());
612 // Completion is async.
615 void VerifyDeliverSmallAppCachedResponse() {
616 EXPECT_TRUE(request_
->status().is_success());
617 EXPECT_TRUE(CompareHttpResponseInfos(
618 write_info_buffer_
->http_info
.get(),
619 &url_request_delegate_
->received_info_
));
620 EXPECT_EQ(5, url_request_delegate_
->amount_received_
);
621 EXPECT_EQ(0, memcmp(kHttpBasicBody
,
622 url_request_delegate_
->received_data_
->data(),
623 strlen(kHttpBasicBody
)));
627 // DeliverLargeAppCachedResponse --------------------------------------
628 // "Large" enough to require multiple calls to request->Read to complete.
630 void DeliverLargeAppCachedResponse() {
631 // This test has several async steps.
632 // 1. Write a large response to response storage.
633 // 2. Use net::URLRequest to retrieve it.
634 // 3. Verify we received what we expected to receive.
636 PushNextTask(base::Bind(
637 &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse
,
638 base::Unretained(this)));
639 PushNextTask(base::Bind(
640 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
641 base::Unretained(this), true));
643 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
644 written_response_id_
= writer_
->response_id();
645 WriteLargeResponse();
649 void WriteLargeResponse() {
651 static const char kHttpHeaders
[] =
652 "HTTP/1.0 200 OK\0Content-Length: 3072\0\0";
653 scoped_refptr
<IOBuffer
> body(new IOBuffer(kBlockSize
* 3));
654 char* p
= body
->data();
655 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
656 FillData(i
+ 1, p
, kBlockSize
);
657 std::string
raw_headers(kHttpHeaders
, arraysize(kHttpHeaders
));
659 MakeHttpResponseInfo(raw_headers
), body
.get(), kBlockSize
* 3);
662 void VerifyDeliverLargeAppCachedResponse() {
663 EXPECT_TRUE(request_
->status().is_success());
664 EXPECT_TRUE(CompareHttpResponseInfos(
665 write_info_buffer_
->http_info
.get(),
666 &url_request_delegate_
->received_info_
));
667 EXPECT_EQ(3072, url_request_delegate_
->amount_received_
);
668 char* p
= url_request_delegate_
->received_data_
->data();
669 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
670 EXPECT_TRUE(CheckData(i
+ 1, p
, kBlockSize
));
674 // DeliverPartialResponse --------------------------------------
676 void DeliverPartialResponse() {
677 // This test has several async steps.
678 // 1. Write a small response to response storage.
679 // 2. Use net::URLRequest to retrieve it a subset using a range request
680 // 3. Verify we received what we expected to receive.
681 PushNextTask(base::Bind(
682 &AppCacheURLRequestJobTest::VerifyDeliverPartialResponse
,
683 base::Unretained(this)));
684 PushNextTask(base::Bind(
685 &AppCacheURLRequestJobTest::MakeRangeRequest
, base::Unretained(this)));
686 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
687 written_response_id_
= writer_
->response_id();
688 WriteBasicResponse();
692 void MakeRangeRequest() {
693 AppCacheStorage
* storage
= service_
->storage();
694 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
695 net::DEFAULT_PRIORITY
,
696 url_request_delegate_
.get(),
699 // Request a range, the 3 middle chars out of 'Hello'
700 net::HttpRequestHeaders extra_headers
;
701 extra_headers
.SetHeader("Range", "bytes= 1-3");
702 request_
->SetExtraRequestHeaders(extra_headers
);
704 // Create job with orders to deliver an appcached entry.
705 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
706 request_
.get(), NULL
, storage
, NULL
, false));
707 job
->DeliverAppCachedResponse(
709 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
711 EXPECT_TRUE(job
->is_delivering_appcache_response());
713 // Start the request.
714 EXPECT_FALSE(job
->has_been_started());
715 job_factory_
->SetJob(job
.get());
717 EXPECT_FALSE(job_factory_
->has_job());
718 EXPECT_TRUE(job
->has_been_started());
719 // Completion is async.
722 void VerifyDeliverPartialResponse() {
723 EXPECT_TRUE(request_
->status().is_success());
724 EXPECT_EQ(3, url_request_delegate_
->amount_received_
);
725 EXPECT_EQ(0, memcmp(kHttpBasicBody
+ 1,
726 url_request_delegate_
->received_data_
->data(),
728 net::HttpResponseHeaders
* headers
=
729 url_request_delegate_
->received_info_
.headers
.get();
730 EXPECT_EQ(206, headers
->response_code());
731 EXPECT_EQ(3, headers
->GetContentLength());
732 int64 range_start
, range_end
, object_size
;
734 headers
->GetContentRange(&range_start
, &range_end
, &object_size
));
735 EXPECT_EQ(1, range_start
);
736 EXPECT_EQ(3, range_end
);
737 EXPECT_EQ(5, object_size
);
741 // CancelRequest --------------------------------------
743 void CancelRequest() {
744 // This test has several async steps.
745 // 1. Write a large response to response storage.
746 // 2. Use net::URLRequest to retrieve it.
747 // 3. Cancel the request after data starts coming in.
749 PushNextTask(base::Bind(
750 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
751 PushNextTask(base::Bind(
752 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
753 base::Unretained(this), true));
755 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
756 written_response_id_
= writer_
->response_id();
757 WriteLargeResponse();
759 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
760 url_request_delegate_
->kill_with_io_pending_
= false;
764 void VerifyCancel() {
765 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
766 request_
->status().status());
770 // CancelRequestWithIOPending --------------------------------------
772 void CancelRequestWithIOPending() {
773 // This test has several async steps.
774 // 1. Write a large response to response storage.
775 // 2. Use net::URLRequest to retrieve it.
776 // 3. Cancel the request after data starts coming in.
778 PushNextTask(base::Bind(
779 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
780 PushNextTask(base::Bind(
781 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
782 base::Unretained(this), true));
784 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
785 written_response_id_
= writer_
->response_id();
786 WriteLargeResponse();
788 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
789 url_request_delegate_
->kill_with_io_pending_
= true;
794 // Data members --------------------------------------------------------
796 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
797 scoped_ptr
<MockStorageDelegate
> storage_delegate_
;
798 scoped_ptr
<MockAppCacheService
> service_
;
799 std::stack
<std::pair
<base::Closure
, bool> > task_stack_
;
801 scoped_ptr
<AppCacheResponseReader
> reader_
;
802 scoped_refptr
<HttpResponseInfoIOBuffer
> read_info_buffer_
;
803 scoped_refptr
<IOBuffer
> read_buffer_
;
804 int expected_read_result_
;
805 int reader_deletion_count_down_
;
807 int64 written_response_id_
;
808 scoped_ptr
<AppCacheResponseWriter
> writer_
;
809 scoped_refptr
<HttpResponseInfoIOBuffer
> write_info_buffer_
;
810 scoped_refptr
<IOBuffer
> write_buffer_
;
811 int expected_write_result_
;
812 int writer_deletion_count_down_
;
814 scoped_ptr
<MockURLRequestJobFactory
> job_factory_
;
815 scoped_ptr
<net::URLRequestContext
> empty_context_
;
816 scoped_ptr
<net::URLRequest
> request_
;
817 scoped_ptr
<MockURLRequestDelegate
> url_request_delegate_
;
819 static scoped_ptr
<base::Thread
> io_thread_
;
823 scoped_ptr
<base::Thread
> AppCacheURLRequestJobTest::io_thread_
;
825 TEST_F(AppCacheURLRequestJobTest
, Basic
) {
826 RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic
);
829 TEST_F(AppCacheURLRequestJobTest
, DeliveryOrders
) {
830 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders
);
833 TEST_F(AppCacheURLRequestJobTest
, DeliverNetworkResponse
) {
834 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse
);
837 TEST_F(AppCacheURLRequestJobTest
, DeliverErrorResponse
) {
838 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse
);
841 TEST_F(AppCacheURLRequestJobTest
, DeliverSmallAppCachedResponse
) {
842 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse
);
845 TEST_F(AppCacheURLRequestJobTest
, DeliverLargeAppCachedResponse
) {
846 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse
);
849 TEST_F(AppCacheURLRequestJobTest
, DeliverPartialResponse
) {
850 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse
);
853 TEST_F(AppCacheURLRequestJobTest
, CancelRequest
) {
854 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest
);
857 TEST_F(AppCacheURLRequestJobTest
, CancelRequestWithIOPending
) {
858 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending
);
863 } // namespace content