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 ~MockURLRequestJobFactory() override
{ DCHECK(!job_
); }
51 void SetJob(net::URLRequestJob
* job
) {
55 bool has_job() const {
59 // net::URLRequestJobFactory implementation.
60 net::URLRequestJob
* MaybeCreateJobWithProtocolHandler(
61 const std::string
& scheme
,
62 net::URLRequest
* request
,
63 net::NetworkDelegate
* network_delegate
) const override
{
65 net::URLRequestJob
* temp
= job_
;
69 return new net::URLRequestErrorJob(request
,
71 net::ERR_INTERNET_DISCONNECTED
);
75 bool IsHandledProtocol(const std::string
& scheme
) const override
{
76 return scheme
== "http";
79 bool IsHandledURL(const GURL
& url
) const override
{
80 return url
.SchemeIs("http");
83 bool IsSafeRedirectTarget(const GURL
& location
) const override
{
88 mutable net::URLRequestJob
* job_
;
91 class AppCacheURLRequestJobTest
: public testing::Test
{
94 // Test Harness -------------------------------------------------------------
95 // TODO(michaeln): share this test harness with AppCacheResponseTest
97 class MockStorageDelegate
: public AppCacheStorage::Delegate
{
99 explicit MockStorageDelegate(AppCacheURLRequestJobTest
* test
)
100 : loaded_info_id_(0), test_(test
) {
103 void OnResponseInfoLoaded(AppCacheResponseInfo
* info
,
104 int64 response_id
) override
{
106 loaded_info_id_
= response_id
;
107 test_
->ScheduleNextTask();
110 scoped_refptr
<AppCacheResponseInfo
> loaded_info_
;
111 int64 loaded_info_id_
;
112 AppCacheURLRequestJobTest
* test_
;
115 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
117 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest
* test
)
119 received_data_(new net::IOBuffer(kNumBlocks
* kBlockSize
)),
120 did_receive_headers_(false), amount_received_(0),
121 kill_after_amount_received_(0), kill_with_io_pending_(false) {
124 void OnResponseStarted(net::URLRequest
* request
) override
{
125 amount_received_
= 0;
126 did_receive_headers_
= false;
127 if (request
->status().is_success()) {
128 EXPECT_TRUE(request
->response_headers());
129 did_receive_headers_
= true;
130 received_info_
= request
->response_info();
137 void OnReadCompleted(net::URLRequest
* request
, int bytes_read
) override
{
138 if (bytes_read
> 0) {
139 amount_received_
+= bytes_read
;
141 if (kill_after_amount_received_
&& !kill_with_io_pending_
) {
142 if (amount_received_
>= kill_after_amount_received_
) {
150 if (kill_after_amount_received_
&& kill_with_io_pending_
) {
151 if (amount_received_
>= kill_after_amount_received_
) {
161 void ReadSome(net::URLRequest
* request
) {
162 DCHECK(amount_received_
+ kBlockSize
<= kNumBlocks
* kBlockSize
);
163 scoped_refptr
<IOBuffer
> wrapped_buffer(
164 new net::WrappedIOBuffer(received_data_
->data() + amount_received_
));
167 request
->Read(wrapped_buffer
.get(), kBlockSize
, &bytes_read
));
168 EXPECT_EQ(0, bytes_read
);
171 void RequestComplete() {
172 test_
->ScheduleNextTask();
175 AppCacheURLRequestJobTest
* test_
;
176 net::HttpResponseInfo received_info_
;
177 scoped_refptr
<net::IOBuffer
> received_data_
;
178 bool did_receive_headers_
;
179 int amount_received_
;
180 int kill_after_amount_received_
;
181 bool kill_with_io_pending_
;
184 // Helper callback to run a test on our io_thread. The io_thread is spun up
185 // once and reused for all tests.
186 template <class Method
>
187 void MethodWrapper(Method method
) {
192 static void SetUpTestCase() {
193 io_thread_
.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
194 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
195 io_thread_
->StartWithOptions(options
);
198 static void TearDownTestCase() {
199 io_thread_
.reset(NULL
);
202 AppCacheURLRequestJobTest() {}
204 template <class Method
>
205 void RunTestOnIOThread(Method method
) {
206 test_finished_event_
.reset(new base::WaitableEvent(false, false));
207 io_thread_
->message_loop()->PostTask(
208 FROM_HERE
, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper
<Method
>,
209 base::Unretained(this), method
));
210 test_finished_event_
->Wait();
214 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
215 DCHECK(task_stack_
.empty());
217 storage_delegate_
.reset(new MockStorageDelegate(this));
218 service_
.reset(new MockAppCacheService());
219 expected_read_result_
= 0;
220 expected_write_result_
= 0;
221 written_response_id_
= 0;
222 reader_deletion_count_down_
= 0;
223 writer_deletion_count_down_
= 0;
225 url_request_delegate_
.reset(new MockURLRequestDelegate(this));
226 job_factory_
.reset(new MockURLRequestJobFactory());
227 empty_context_
.reset(new net::URLRequestContext());
228 empty_context_
->set_job_factory(job_factory_
.get());
231 void TearDownTest() {
232 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
235 while (!task_stack_
.empty())
240 read_info_buffer_
= NULL
;
242 write_buffer_
= NULL
;
243 write_info_buffer_
= NULL
;
244 storage_delegate_
.reset();
247 DCHECK(!job_factory_
->has_job());
248 empty_context_
.reset();
249 job_factory_
.reset();
250 url_request_delegate_
.reset();
253 void TestFinished() {
254 // We unwind the stack prior to finishing up to let stack
255 // based objects get deleted.
256 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
257 base::MessageLoop::current()->PostTask(
259 base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound
,
260 base::Unretained(this)));
263 void TestFinishedUnwound() {
265 test_finished_event_
->Signal();
268 void PushNextTask(const base::Closure
& task
) {
269 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, false));
272 void PushNextTaskAsImmediate(const base::Closure
& task
) {
273 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, true));
276 void ScheduleNextTask() {
277 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
278 if (task_stack_
.empty()) {
282 base::Closure task
=task_stack_
.top().first
;
283 bool immediate
= task_stack_
.top().second
;
288 base::MessageLoop::current()->PostTask(FROM_HERE
, task
);
291 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
293 void WriteBasicResponse() {
294 scoped_refptr
<IOBuffer
> body(new WrappedIOBuffer(kHttpBasicBody
));
295 std::string
raw_headers(kHttpBasicHeaders
, arraysize(kHttpBasicHeaders
));
297 MakeHttpResponseInfo(raw_headers
), body
.get(), strlen(kHttpBasicBody
));
300 void WriteResponse(net::HttpResponseInfo
* head
,
301 IOBuffer
* body
, int body_len
) {
303 scoped_refptr
<IOBuffer
> body_ref(body
);
304 PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody
,
305 base::Unretained(this), body_ref
, body_len
));
306 WriteResponseHead(head
);
309 void WriteResponseHead(net::HttpResponseInfo
* head
) {
310 EXPECT_FALSE(writer_
->IsWritePending());
311 expected_write_result_
= GetHttpResponseInfoSize(head
);
312 write_info_buffer_
= new HttpResponseInfoIOBuffer(head
);
314 write_info_buffer_
.get(),
315 base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete
,
316 base::Unretained(this)));
319 void WriteResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
320 EXPECT_FALSE(writer_
->IsWritePending());
321 write_buffer_
= io_buffer
;
322 expected_write_result_
= buf_len
;
323 writer_
->WriteData(write_buffer_
.get(),
325 base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete
,
326 base::Unretained(this)));
329 void ReadResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
330 EXPECT_FALSE(reader_
->IsReadPending());
331 read_buffer_
= io_buffer
;
332 expected_read_result_
= buf_len
;
333 reader_
->ReadData(read_buffer_
.get(),
335 base::Bind(&AppCacheURLRequestJobTest::OnReadComplete
,
336 base::Unretained(this)));
339 // AppCacheResponseReader / Writer completion callbacks
341 void OnWriteInfoComplete(int result
) {
342 EXPECT_FALSE(writer_
->IsWritePending());
343 EXPECT_EQ(expected_write_result_
, result
);
347 void OnWriteComplete(int result
) {
348 EXPECT_FALSE(writer_
->IsWritePending());
349 EXPECT_EQ(expected_write_result_
, result
);
353 void OnReadInfoComplete(int result
) {
354 EXPECT_FALSE(reader_
->IsReadPending());
355 EXPECT_EQ(expected_read_result_
, result
);
359 void OnReadComplete(int result
) {
360 EXPECT_FALSE(reader_
->IsReadPending());
361 EXPECT_EQ(expected_read_result_
, result
);
365 // Helpers to work with HttpResponseInfo objects
367 net::HttpResponseInfo
* MakeHttpResponseInfo(const std::string
& raw_headers
) {
368 net::HttpResponseInfo
* info
= new net::HttpResponseInfo
;
369 info
->request_time
= base::Time::Now();
370 info
->response_time
= base::Time::Now();
371 info
->was_cached
= false;
372 info
->headers
= new net::HttpResponseHeaders(raw_headers
);
376 int GetHttpResponseInfoSize(const net::HttpResponseInfo
* info
) {
378 return PickleHttpResonseInfo(&pickle
, info
);
381 bool CompareHttpResponseInfos(const net::HttpResponseInfo
* info1
,
382 const net::HttpResponseInfo
* info2
) {
385 PickleHttpResonseInfo(&pickle1
, info1
);
386 PickleHttpResonseInfo(&pickle2
, info2
);
387 return (pickle1
.size() == pickle2
.size()) &&
388 (0 == memcmp(pickle1
.data(), pickle2
.data(), pickle1
.size()));
391 int PickleHttpResonseInfo(Pickle
* pickle
, const net::HttpResponseInfo
* info
) {
392 const bool kSkipTransientHeaders
= true;
393 const bool kTruncated
= false;
394 info
->Persist(pickle
, kSkipTransientHeaders
, kTruncated
);
395 return pickle
->size();
398 // Helpers to fill and verify blocks of memory with a value
400 void FillData(char value
, char* data
, int data_len
) {
401 memset(data
, value
, data_len
);
404 bool CheckData(char value
, const char* data
, int data_len
) {
405 for (int i
= 0; i
< data_len
; ++i
, ++data
) {
412 // Individual Tests ---------------------------------------------------------
413 // Some of the individual tests involve multiple async steps. Each test
414 // is delineated with a section header.
416 // Basic -------------------------------------------------------------------
418 AppCacheStorage
* storage
= service_
->storage();
419 scoped_ptr
<net::URLRequest
> request(empty_context_
->CreateRequest(
420 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
, NULL
));
421 scoped_refptr
<AppCacheURLRequestJob
> job
;
423 // Create an instance and see that it looks as expected.
425 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
426 EXPECT_TRUE(job
->is_waiting());
427 EXPECT_FALSE(job
->is_delivering_appcache_response());
428 EXPECT_FALSE(job
->is_delivering_network_response());
429 EXPECT_FALSE(job
->is_delivering_error_response());
430 EXPECT_FALSE(job
->has_been_started());
431 EXPECT_FALSE(job
->has_been_killed());
432 EXPECT_EQ(GURL(), job
->manifest_url());
433 EXPECT_EQ(kAppCacheNoCacheId
, job
->cache_id());
434 EXPECT_FALSE(job
->entry().has_response_id());
439 // DeliveryOrders -----------------------------------------------------
440 void DeliveryOrders() {
441 AppCacheStorage
* storage
= service_
->storage();
442 scoped_ptr
<net::URLRequest
> request(empty_context_
->CreateRequest(
443 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
, NULL
));
444 scoped_refptr
<AppCacheURLRequestJob
> job
;
446 // Create an instance, give it a delivery order and see that
447 // it looks as expected.
449 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
450 job
->DeliverErrorResponse();
451 EXPECT_TRUE(job
->is_delivering_error_response());
452 EXPECT_FALSE(job
->has_been_started());
454 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
455 job
->DeliverNetworkResponse();
456 EXPECT_TRUE(job
->is_delivering_network_response());
457 EXPECT_FALSE(job
->has_been_started());
459 job
= new AppCacheURLRequestJob(request
.get(), NULL
, storage
, NULL
, false);
460 const GURL
kManifestUrl("http://blah/");
461 const int64
kCacheId(1);
462 const int64
kGroupId(1);
463 const AppCacheEntry
kEntry(AppCacheEntry::EXPLICIT
, 1);
464 job
->DeliverAppCachedResponse(kManifestUrl
, kCacheId
, kGroupId
,
466 EXPECT_FALSE(job
->is_waiting());
467 EXPECT_TRUE(job
->is_delivering_appcache_response());
468 EXPECT_FALSE(job
->has_been_started());
469 EXPECT_EQ(kManifestUrl
, job
->manifest_url());
470 EXPECT_EQ(kCacheId
, job
->cache_id());
471 EXPECT_EQ(kGroupId
, job
->group_id());
472 EXPECT_EQ(kEntry
.types(), job
->entry().types());
473 EXPECT_EQ(kEntry
.response_id(), job
->entry().response_id());
478 // DeliverNetworkResponse --------------------------------------------------
480 void DeliverNetworkResponse() {
481 // This test has async steps.
483 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse
,
484 base::Unretained(this)));
486 AppCacheStorage
* storage
= service_
->storage();
487 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
488 net::DEFAULT_PRIORITY
,
489 url_request_delegate_
.get(),
492 // Setup to create an AppCacheURLRequestJob with orders to deliver
493 // a network response.
494 AppCacheURLRequestJob
* mock_job
= new AppCacheURLRequestJob(
495 request_
.get(), NULL
, storage
, NULL
, false);
496 job_factory_
->SetJob(mock_job
);
497 mock_job
->DeliverNetworkResponse();
498 EXPECT_TRUE(mock_job
->is_delivering_network_response());
499 EXPECT_FALSE(mock_job
->has_been_started());
501 // Start the request.
504 // The job should have been picked up.
505 EXPECT_FALSE(job_factory_
->has_job());
506 // Completion is async.
509 void VerifyDeliverNetworkResponse() {
510 EXPECT_EQ(request_
->status().error(),
511 net::ERR_INTERNET_DISCONNECTED
);
515 // DeliverErrorResponse --------------------------------------------------
517 void DeliverErrorResponse() {
518 // This test has async steps.
520 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse
,
521 base::Unretained(this)));
523 AppCacheStorage
* storage
= service_
->storage();
524 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
525 net::DEFAULT_PRIORITY
,
526 url_request_delegate_
.get(),
529 // Setup to create an AppCacheURLRequestJob with orders to deliver
530 // a network response.
531 AppCacheURLRequestJob
* mock_job
= new AppCacheURLRequestJob(
532 request_
.get(), NULL
, storage
, NULL
, false);
533 job_factory_
->SetJob(mock_job
);
534 mock_job
->DeliverErrorResponse();
535 EXPECT_TRUE(mock_job
->is_delivering_error_response());
536 EXPECT_FALSE(mock_job
->has_been_started());
538 // Start the request.
541 // The job should have been picked up.
542 EXPECT_FALSE(job_factory_
->has_job());
543 // Completion is async.
546 void VerifyDeliverErrorResponse() {
547 EXPECT_EQ(request_
->status().error(), net::ERR_FAILED
);
551 // DeliverSmallAppCachedResponse --------------------------------------
552 // "Small" being small enough to read completely in a single
553 // request->Read call.
555 void DeliverSmallAppCachedResponse() {
556 // This test has several async steps.
557 // 1. Write a small response to response storage.
558 // 2. Use net::URLRequest to retrieve it.
559 // 3. Verify we received what we expected to receive.
561 PushNextTask(base::Bind(
562 &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse
,
563 base::Unretained(this)));
565 base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource
,
566 base::Unretained(this), false));
568 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
569 written_response_id_
= writer_
->response_id();
570 WriteBasicResponse();
574 void RequestAppCachedResource(bool start_after_delivery_orders
) {
575 AppCacheStorage
* storage
= service_
->storage();
576 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
577 net::DEFAULT_PRIORITY
,
578 url_request_delegate_
.get(),
581 // Setup to create an AppCacheURLRequestJob with orders to deliver
582 // a network response.
583 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
584 request_
.get(), NULL
, storage
, NULL
, false));
586 if (start_after_delivery_orders
) {
587 job
->DeliverAppCachedResponse(
589 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
591 EXPECT_TRUE(job
->is_delivering_appcache_response());
594 // Start the request.
595 EXPECT_FALSE(job
->has_been_started());
596 job_factory_
->SetJob(job
.get());
598 EXPECT_FALSE(job_factory_
->has_job());
599 EXPECT_TRUE(job
->has_been_started());
601 if (!start_after_delivery_orders
) {
602 job
->DeliverAppCachedResponse(
604 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
606 EXPECT_TRUE(job
->is_delivering_appcache_response());
609 // Completion is async.
612 void VerifyDeliverSmallAppCachedResponse() {
613 EXPECT_TRUE(request_
->status().is_success());
614 EXPECT_TRUE(CompareHttpResponseInfos(
615 write_info_buffer_
->http_info
.get(),
616 &url_request_delegate_
->received_info_
));
617 EXPECT_EQ(5, url_request_delegate_
->amount_received_
);
618 EXPECT_EQ(0, memcmp(kHttpBasicBody
,
619 url_request_delegate_
->received_data_
->data(),
620 strlen(kHttpBasicBody
)));
624 // DeliverLargeAppCachedResponse --------------------------------------
625 // "Large" enough to require multiple calls to request->Read to complete.
627 void DeliverLargeAppCachedResponse() {
628 // This test has several async steps.
629 // 1. Write a large response to response storage.
630 // 2. Use net::URLRequest to retrieve it.
631 // 3. Verify we received what we expected to receive.
633 PushNextTask(base::Bind(
634 &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse
,
635 base::Unretained(this)));
636 PushNextTask(base::Bind(
637 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
638 base::Unretained(this), true));
640 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
641 written_response_id_
= writer_
->response_id();
642 WriteLargeResponse();
646 void WriteLargeResponse() {
648 static const char kHttpHeaders
[] =
649 "HTTP/1.0 200 OK\0Content-Length: 3072\0\0";
650 scoped_refptr
<IOBuffer
> body(new IOBuffer(kBlockSize
* 3));
651 char* p
= body
->data();
652 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
653 FillData(i
+ 1, p
, kBlockSize
);
654 std::string
raw_headers(kHttpHeaders
, arraysize(kHttpHeaders
));
656 MakeHttpResponseInfo(raw_headers
), body
.get(), kBlockSize
* 3);
659 void VerifyDeliverLargeAppCachedResponse() {
660 EXPECT_TRUE(request_
->status().is_success());
661 EXPECT_TRUE(CompareHttpResponseInfos(
662 write_info_buffer_
->http_info
.get(),
663 &url_request_delegate_
->received_info_
));
664 EXPECT_EQ(3072, url_request_delegate_
->amount_received_
);
665 char* p
= url_request_delegate_
->received_data_
->data();
666 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
667 EXPECT_TRUE(CheckData(i
+ 1, p
, kBlockSize
));
671 // DeliverPartialResponse --------------------------------------
673 void DeliverPartialResponse() {
674 // This test has several async steps.
675 // 1. Write a small response to response storage.
676 // 2. Use net::URLRequest to retrieve it a subset using a range request
677 // 3. Verify we received what we expected to receive.
678 PushNextTask(base::Bind(
679 &AppCacheURLRequestJobTest::VerifyDeliverPartialResponse
,
680 base::Unretained(this)));
681 PushNextTask(base::Bind(
682 &AppCacheURLRequestJobTest::MakeRangeRequest
, base::Unretained(this)));
683 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
684 written_response_id_
= writer_
->response_id();
685 WriteBasicResponse();
689 void MakeRangeRequest() {
690 AppCacheStorage
* storage
= service_
->storage();
691 request_
= empty_context_
->CreateRequest(GURL("http://blah/"),
692 net::DEFAULT_PRIORITY
,
693 url_request_delegate_
.get(),
696 // Request a range, the 3 middle chars out of 'Hello'
697 net::HttpRequestHeaders extra_headers
;
698 extra_headers
.SetHeader("Range", "bytes= 1-3");
699 request_
->SetExtraRequestHeaders(extra_headers
);
701 // Create job with orders to deliver an appcached entry.
702 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
703 request_
.get(), NULL
, storage
, NULL
, false));
704 job
->DeliverAppCachedResponse(
706 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
708 EXPECT_TRUE(job
->is_delivering_appcache_response());
710 // Start the request.
711 EXPECT_FALSE(job
->has_been_started());
712 job_factory_
->SetJob(job
.get());
714 EXPECT_FALSE(job_factory_
->has_job());
715 EXPECT_TRUE(job
->has_been_started());
716 // Completion is async.
719 void VerifyDeliverPartialResponse() {
720 EXPECT_TRUE(request_
->status().is_success());
721 EXPECT_EQ(3, url_request_delegate_
->amount_received_
);
722 EXPECT_EQ(0, memcmp(kHttpBasicBody
+ 1,
723 url_request_delegate_
->received_data_
->data(),
725 net::HttpResponseHeaders
* headers
=
726 url_request_delegate_
->received_info_
.headers
.get();
727 EXPECT_EQ(206, headers
->response_code());
728 EXPECT_EQ(3, headers
->GetContentLength());
729 int64 range_start
, range_end
, object_size
;
731 headers
->GetContentRange(&range_start
, &range_end
, &object_size
));
732 EXPECT_EQ(1, range_start
);
733 EXPECT_EQ(3, range_end
);
734 EXPECT_EQ(5, object_size
);
738 // CancelRequest --------------------------------------
740 void CancelRequest() {
741 // This test has several async steps.
742 // 1. Write a large response to response storage.
743 // 2. Use net::URLRequest to retrieve it.
744 // 3. Cancel the request after data starts coming in.
746 PushNextTask(base::Bind(
747 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
748 PushNextTask(base::Bind(
749 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
750 base::Unretained(this), true));
752 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
753 written_response_id_
= writer_
->response_id();
754 WriteLargeResponse();
756 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
757 url_request_delegate_
->kill_with_io_pending_
= false;
761 void VerifyCancel() {
762 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
763 request_
->status().status());
767 // CancelRequestWithIOPending --------------------------------------
769 void CancelRequestWithIOPending() {
770 // This test has several async steps.
771 // 1. Write a large response to response storage.
772 // 2. Use net::URLRequest to retrieve it.
773 // 3. Cancel the request after data starts coming in.
775 PushNextTask(base::Bind(
776 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
777 PushNextTask(base::Bind(
778 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
779 base::Unretained(this), true));
781 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
782 written_response_id_
= writer_
->response_id();
783 WriteLargeResponse();
785 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
786 url_request_delegate_
->kill_with_io_pending_
= true;
791 // Data members --------------------------------------------------------
793 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
794 scoped_ptr
<MockStorageDelegate
> storage_delegate_
;
795 scoped_ptr
<MockAppCacheService
> service_
;
796 std::stack
<std::pair
<base::Closure
, bool> > task_stack_
;
798 scoped_ptr
<AppCacheResponseReader
> reader_
;
799 scoped_refptr
<HttpResponseInfoIOBuffer
> read_info_buffer_
;
800 scoped_refptr
<IOBuffer
> read_buffer_
;
801 int expected_read_result_
;
802 int reader_deletion_count_down_
;
804 int64 written_response_id_
;
805 scoped_ptr
<AppCacheResponseWriter
> writer_
;
806 scoped_refptr
<HttpResponseInfoIOBuffer
> write_info_buffer_
;
807 scoped_refptr
<IOBuffer
> write_buffer_
;
808 int expected_write_result_
;
809 int writer_deletion_count_down_
;
811 scoped_ptr
<MockURLRequestJobFactory
> job_factory_
;
812 scoped_ptr
<net::URLRequestContext
> empty_context_
;
813 scoped_ptr
<net::URLRequest
> request_
;
814 scoped_ptr
<MockURLRequestDelegate
> url_request_delegate_
;
816 static scoped_ptr
<base::Thread
> io_thread_
;
820 scoped_ptr
<base::Thread
> AppCacheURLRequestJobTest::io_thread_
;
822 TEST_F(AppCacheURLRequestJobTest
, Basic
) {
823 RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic
);
826 TEST_F(AppCacheURLRequestJobTest
, DeliveryOrders
) {
827 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders
);
830 TEST_F(AppCacheURLRequestJobTest
, DeliverNetworkResponse
) {
831 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse
);
834 TEST_F(AppCacheURLRequestJobTest
, DeliverErrorResponse
) {
835 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse
);
838 TEST_F(AppCacheURLRequestJobTest
, DeliverSmallAppCachedResponse
) {
839 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse
);
842 TEST_F(AppCacheURLRequestJobTest
, DeliverLargeAppCachedResponse
) {
843 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse
);
846 TEST_F(AppCacheURLRequestJobTest
, DeliverPartialResponse
) {
847 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse
);
850 TEST_F(AppCacheURLRequestJobTest
, CancelRequest
) {
851 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest
);
854 TEST_F(AppCacheURLRequestJobTest
, CancelRequestWithIOPending
) {
855 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending
);
860 } // namespace content