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/pickle.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "content/browser/appcache/mock_appcache_service.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/request_priority.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/url_request/url_request.h"
21 #include "net/url_request/url_request_context.h"
22 #include "net/url_request/url_request_error_job.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "webkit/browser/appcache/appcache_response.h"
25 #include "webkit/browser/appcache/appcache_url_request_job.h"
27 using appcache::AppCacheEntry
;
28 using appcache::AppCacheStorage
;
29 using appcache::AppCacheResponseInfo
;
30 using appcache::AppCacheResponseReader
;
31 using appcache::AppCacheResponseWriter
;
32 using appcache::AppCacheURLRequestJob
;
33 using appcache::HttpResponseInfoIOBuffer
;
34 using appcache::kNoCacheId
;
36 using net::WrappedIOBuffer
;
40 static const char kHttpBasicHeaders
[] =
41 "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
42 static const char kHttpBasicBody
[] = "Hello";
44 static const int kNumBlocks
= 4;
45 static const int kBlockSize
= 1024;
47 class AppCacheURLRequestJobTest
: public testing::Test
{
50 // Test Harness -------------------------------------------------------------
51 // TODO(michaeln): share this test harness with AppCacheResponseTest
53 class MockStorageDelegate
: public AppCacheStorage::Delegate
{
55 explicit MockStorageDelegate(AppCacheURLRequestJobTest
* test
)
56 : loaded_info_id_(0), test_(test
) {
59 virtual void OnResponseInfoLoaded(AppCacheResponseInfo
* info
,
60 int64 response_id
) OVERRIDE
{
62 loaded_info_id_
= response_id
;
63 test_
->ScheduleNextTask();
66 scoped_refptr
<AppCacheResponseInfo
> loaded_info_
;
67 int64 loaded_info_id_
;
68 AppCacheURLRequestJobTest
* test_
;
71 class MockURLRequestDelegate
: public net::URLRequest::Delegate
{
73 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest
* test
)
75 received_data_(new net::IOBuffer(kNumBlocks
* kBlockSize
)),
76 did_receive_headers_(false), amount_received_(0),
77 kill_after_amount_received_(0), kill_with_io_pending_(false) {
80 virtual void OnResponseStarted(net::URLRequest
* request
) OVERRIDE
{
82 did_receive_headers_
= false;
83 if (request
->status().is_success()) {
84 EXPECT_TRUE(request
->response_headers());
85 did_receive_headers_
= true;
86 received_info_
= request
->response_info();
93 virtual void OnReadCompleted(net::URLRequest
* request
,
94 int bytes_read
) OVERRIDE
{
96 amount_received_
+= bytes_read
;
98 if (kill_after_amount_received_
&& !kill_with_io_pending_
) {
99 if (amount_received_
>= kill_after_amount_received_
) {
107 if (kill_after_amount_received_
&& kill_with_io_pending_
) {
108 if (amount_received_
>= kill_after_amount_received_
) {
118 void ReadSome(net::URLRequest
* request
) {
119 DCHECK(amount_received_
+ kBlockSize
<= kNumBlocks
* kBlockSize
);
120 scoped_refptr
<IOBuffer
> wrapped_buffer(
121 new net::WrappedIOBuffer(received_data_
->data() + amount_received_
));
124 request
->Read(wrapped_buffer
.get(), kBlockSize
, &bytes_read
));
125 EXPECT_EQ(0, bytes_read
);
128 void RequestComplete() {
129 test_
->ScheduleNextTask();
132 AppCacheURLRequestJobTest
* test_
;
133 net::HttpResponseInfo received_info_
;
134 scoped_refptr
<net::IOBuffer
> received_data_
;
135 bool did_receive_headers_
;
136 int amount_received_
;
137 int kill_after_amount_received_
;
138 bool kill_with_io_pending_
;
141 static net::URLRequestJob
* MockHttpJobFactory(
142 net::URLRequest
* request
,
143 net::NetworkDelegate
* network_delegate
,
144 const std::string
& scheme
) {
145 if (mock_factory_job_
) {
146 net::URLRequestJob
* temp
= mock_factory_job_
;
147 mock_factory_job_
= NULL
;
150 return new net::URLRequestErrorJob(request
,
152 net::ERR_INTERNET_DISCONNECTED
);
156 // Helper callback to run a test on our io_thread. The io_thread is spun up
157 // once and reused for all tests.
158 template <class Method
>
159 void MethodWrapper(Method method
) {
164 static void SetUpTestCase() {
165 io_thread_
.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
166 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
167 io_thread_
->StartWithOptions(options
);
170 static void TearDownTestCase() {
171 io_thread_
.reset(NULL
);
174 AppCacheURLRequestJobTest() {}
176 template <class Method
>
177 void RunTestOnIOThread(Method method
) {
178 test_finished_event_
.reset(new base::WaitableEvent(false, false));
179 io_thread_
->message_loop()->PostTask(
180 FROM_HERE
, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper
<Method
>,
181 base::Unretained(this), method
));
182 test_finished_event_
->Wait();
186 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
187 DCHECK(task_stack_
.empty());
188 orig_http_factory_
= net::URLRequest::Deprecated::RegisterProtocolFactory(
189 "http", MockHttpJobFactory
);
190 url_request_delegate_
.reset(new MockURLRequestDelegate(this));
191 storage_delegate_
.reset(new MockStorageDelegate(this));
192 service_
.reset(new MockAppCacheService());
193 expected_read_result_
= 0;
194 expected_write_result_
= 0;
195 written_response_id_
= 0;
196 reader_deletion_count_down_
= 0;
197 writer_deletion_count_down_
= 0;
200 void TearDownTest() {
201 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
202 net::URLRequest::Deprecated::RegisterProtocolFactory("http",
204 orig_http_factory_
= NULL
;
206 url_request_delegate_
.reset();
207 DCHECK(!mock_factory_job_
);
209 while (!task_stack_
.empty())
214 read_info_buffer_
= NULL
;
216 write_buffer_
= NULL
;
217 write_info_buffer_
= NULL
;
218 storage_delegate_
.reset();
222 void TestFinished() {
223 // We unwind the stack prior to finishing up to let stack
224 // based objects get deleted.
225 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
226 base::MessageLoop::current()->PostTask(
228 base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound
,
229 base::Unretained(this)));
232 void TestFinishedUnwound() {
234 test_finished_event_
->Signal();
237 void PushNextTask(const base::Closure
& task
) {
238 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, false));
241 void PushNextTaskAsImmediate(const base::Closure
& task
) {
242 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, true));
245 void ScheduleNextTask() {
246 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
247 if (task_stack_
.empty()) {
251 base::Closure task
=task_stack_
.top().first
;
252 bool immediate
= task_stack_
.top().second
;
257 base::MessageLoop::current()->PostTask(FROM_HERE
, task
);
260 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
262 void WriteBasicResponse() {
263 scoped_refptr
<IOBuffer
> body(new WrappedIOBuffer(kHttpBasicBody
));
264 std::string
raw_headers(kHttpBasicHeaders
, arraysize(kHttpBasicHeaders
));
266 MakeHttpResponseInfo(raw_headers
), body
.get(), strlen(kHttpBasicBody
));
269 void WriteResponse(net::HttpResponseInfo
* head
,
270 IOBuffer
* body
, int body_len
) {
272 scoped_refptr
<IOBuffer
> body_ref(body
);
273 PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody
,
274 base::Unretained(this), body_ref
, body_len
));
275 WriteResponseHead(head
);
278 void WriteResponseHead(net::HttpResponseInfo
* head
) {
279 EXPECT_FALSE(writer_
->IsWritePending());
280 expected_write_result_
= GetHttpResponseInfoSize(head
);
281 write_info_buffer_
= new HttpResponseInfoIOBuffer(head
);
283 write_info_buffer_
.get(),
284 base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete
,
285 base::Unretained(this)));
288 void WriteResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
289 EXPECT_FALSE(writer_
->IsWritePending());
290 write_buffer_
= io_buffer
;
291 expected_write_result_
= buf_len
;
292 writer_
->WriteData(write_buffer_
.get(),
294 base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete
,
295 base::Unretained(this)));
298 void ReadResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
299 EXPECT_FALSE(reader_
->IsReadPending());
300 read_buffer_
= io_buffer
;
301 expected_read_result_
= buf_len
;
302 reader_
->ReadData(read_buffer_
.get(),
304 base::Bind(&AppCacheURLRequestJobTest::OnReadComplete
,
305 base::Unretained(this)));
308 // AppCacheResponseReader / Writer completion callbacks
310 void OnWriteInfoComplete(int result
) {
311 EXPECT_FALSE(writer_
->IsWritePending());
312 EXPECT_EQ(expected_write_result_
, result
);
316 void OnWriteComplete(int result
) {
317 EXPECT_FALSE(writer_
->IsWritePending());
318 EXPECT_EQ(expected_write_result_
, result
);
322 void OnReadInfoComplete(int result
) {
323 EXPECT_FALSE(reader_
->IsReadPending());
324 EXPECT_EQ(expected_read_result_
, result
);
328 void OnReadComplete(int result
) {
329 EXPECT_FALSE(reader_
->IsReadPending());
330 EXPECT_EQ(expected_read_result_
, result
);
334 // Helpers to work with HttpResponseInfo objects
336 net::HttpResponseInfo
* MakeHttpResponseInfo(const std::string
& raw_headers
) {
337 net::HttpResponseInfo
* info
= new net::HttpResponseInfo
;
338 info
->request_time
= base::Time::Now();
339 info
->response_time
= base::Time::Now();
340 info
->was_cached
= false;
341 info
->headers
= new net::HttpResponseHeaders(raw_headers
);
345 int GetHttpResponseInfoSize(const net::HttpResponseInfo
* info
) {
347 return PickleHttpResonseInfo(&pickle
, info
);
350 bool CompareHttpResponseInfos(const net::HttpResponseInfo
* info1
,
351 const net::HttpResponseInfo
* info2
) {
354 PickleHttpResonseInfo(&pickle1
, info1
);
355 PickleHttpResonseInfo(&pickle2
, info2
);
356 return (pickle1
.size() == pickle2
.size()) &&
357 (0 == memcmp(pickle1
.data(), pickle2
.data(), pickle1
.size()));
360 int PickleHttpResonseInfo(Pickle
* pickle
, const net::HttpResponseInfo
* info
) {
361 const bool kSkipTransientHeaders
= true;
362 const bool kTruncated
= false;
363 info
->Persist(pickle
, kSkipTransientHeaders
, kTruncated
);
364 return pickle
->size();
367 // Helpers to fill and verify blocks of memory with a value
369 void FillData(char value
, char* data
, int data_len
) {
370 memset(data
, value
, data_len
);
373 bool CheckData(char value
, const char* data
, int data_len
) {
374 for (int i
= 0; i
< data_len
; ++i
, ++data
) {
381 // Individual Tests ---------------------------------------------------------
382 // Some of the individual tests involve multiple async steps. Each test
383 // is delineated with a section header.
385 // Basic -------------------------------------------------------------------
387 AppCacheStorage
* storage
= service_
->storage();
388 net::URLRequest
request(
389 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
, &empty_context_
);
390 scoped_refptr
<AppCacheURLRequestJob
> job
;
392 // Create an instance and see that it looks as expected.
394 job
= new AppCacheURLRequestJob(
395 &request
, NULL
, storage
, NULL
, false);
396 EXPECT_TRUE(job
->is_waiting());
397 EXPECT_FALSE(job
->is_delivering_appcache_response());
398 EXPECT_FALSE(job
->is_delivering_network_response());
399 EXPECT_FALSE(job
->is_delivering_error_response());
400 EXPECT_FALSE(job
->has_been_started());
401 EXPECT_FALSE(job
->has_been_killed());
402 EXPECT_EQ(GURL(), job
->manifest_url());
403 EXPECT_EQ(kNoCacheId
, job
->cache_id());
404 EXPECT_FALSE(job
->entry().has_response_id());
409 // DeliveryOrders -----------------------------------------------------
410 void DeliveryOrders() {
411 AppCacheStorage
* storage
= service_
->storage();
412 net::URLRequest
request(
413 GURL("http://blah/"), net::DEFAULT_PRIORITY
, NULL
, &empty_context_
);
414 scoped_refptr
<AppCacheURLRequestJob
> job
;
416 // Create an instance, give it a delivery order and see that
417 // it looks as expected.
419 job
= new AppCacheURLRequestJob(&request
, NULL
, storage
, NULL
, false);
420 job
->DeliverErrorResponse();
421 EXPECT_TRUE(job
->is_delivering_error_response());
422 EXPECT_FALSE(job
->has_been_started());
424 job
= new AppCacheURLRequestJob(&request
, NULL
, storage
, NULL
, false);
425 job
->DeliverNetworkResponse();
426 EXPECT_TRUE(job
->is_delivering_network_response());
427 EXPECT_FALSE(job
->has_been_started());
429 job
= new AppCacheURLRequestJob(&request
, NULL
, storage
, NULL
, false);
430 const GURL
kManifestUrl("http://blah/");
431 const int64
kCacheId(1);
432 const int64
kGroupId(1);
433 const AppCacheEntry
kEntry(AppCacheEntry::EXPLICIT
, 1);
434 job
->DeliverAppCachedResponse(kManifestUrl
, kCacheId
, kGroupId
,
436 EXPECT_FALSE(job
->is_waiting());
437 EXPECT_TRUE(job
->is_delivering_appcache_response());
438 EXPECT_FALSE(job
->has_been_started());
439 EXPECT_EQ(kManifestUrl
, job
->manifest_url());
440 EXPECT_EQ(kCacheId
, job
->cache_id());
441 EXPECT_EQ(kGroupId
, job
->group_id());
442 EXPECT_EQ(kEntry
.types(), job
->entry().types());
443 EXPECT_EQ(kEntry
.response_id(), job
->entry().response_id());
448 // DeliverNetworkResponse --------------------------------------------------
450 void DeliverNetworkResponse() {
451 // This test has async steps.
453 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse
,
454 base::Unretained(this)));
456 AppCacheStorage
* storage
= service_
->storage();
457 request_
= empty_context_
.CreateRequest(GURL("http://blah/"),
458 net::DEFAULT_PRIORITY
,
459 url_request_delegate_
.get(),
462 // Setup to create an AppCacheURLRequestJob with orders to deliver
463 // a network response.
464 mock_factory_job_
= new AppCacheURLRequestJob(
465 request_
.get(), NULL
, storage
, NULL
, false);
466 mock_factory_job_
->DeliverNetworkResponse();
467 EXPECT_TRUE(mock_factory_job_
->is_delivering_network_response());
468 EXPECT_FALSE(mock_factory_job_
->has_been_started());
470 // Start the request.
473 // The job should have been picked up.
474 EXPECT_FALSE(mock_factory_job_
);
475 // Completion is async.
478 void VerifyDeliverNetworkResponse() {
479 EXPECT_EQ(request_
->status().error(),
480 net::ERR_INTERNET_DISCONNECTED
);
484 // DeliverErrorResponse --------------------------------------------------
486 void DeliverErrorResponse() {
487 // This test has async steps.
489 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse
,
490 base::Unretained(this)));
492 AppCacheStorage
* storage
= service_
->storage();
493 request_
= empty_context_
.CreateRequest(GURL("http://blah/"),
494 net::DEFAULT_PRIORITY
,
495 url_request_delegate_
.get(),
498 // Setup to create an AppCacheURLRequestJob with orders to deliver
499 // a network response.
500 mock_factory_job_
= new AppCacheURLRequestJob(
501 request_
.get(), NULL
, storage
, NULL
, false);
502 mock_factory_job_
->DeliverErrorResponse();
503 EXPECT_TRUE(mock_factory_job_
->is_delivering_error_response());
504 EXPECT_FALSE(mock_factory_job_
->has_been_started());
506 // Start the request.
509 // The job should have been picked up.
510 EXPECT_FALSE(mock_factory_job_
);
511 // Completion is async.
514 void VerifyDeliverErrorResponse() {
515 EXPECT_EQ(request_
->status().error(), net::ERR_FAILED
);
519 // DeliverSmallAppCachedResponse --------------------------------------
520 // "Small" being small enough to read completely in a single
521 // request->Read call.
523 void DeliverSmallAppCachedResponse() {
524 // This test has several async steps.
525 // 1. Write a small response to response storage.
526 // 2. Use net::URLRequest to retrieve it.
527 // 3. Verify we received what we expected to receive.
529 PushNextTask(base::Bind(
530 &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse
,
531 base::Unretained(this)));
533 base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource
,
534 base::Unretained(this), false));
536 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
537 written_response_id_
= writer_
->response_id();
538 WriteBasicResponse();
542 void RequestAppCachedResource(bool start_after_delivery_orders
) {
543 AppCacheStorage
* storage
= service_
->storage();
544 request_
= empty_context_
.CreateRequest(GURL("http://blah/"),
545 net::DEFAULT_PRIORITY
,
546 url_request_delegate_
.get(),
549 // Setup to create an AppCacheURLRequestJob with orders to deliver
550 // a network response.
551 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
552 request_
.get(), NULL
, storage
, NULL
, false));
554 if (start_after_delivery_orders
) {
555 job
->DeliverAppCachedResponse(
557 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
559 EXPECT_TRUE(job
->is_delivering_appcache_response());
562 // Start the request.
563 EXPECT_FALSE(job
->has_been_started());
564 mock_factory_job_
= job
.get();
566 EXPECT_FALSE(mock_factory_job_
);
567 EXPECT_TRUE(job
->has_been_started());
569 if (!start_after_delivery_orders
) {
570 job
->DeliverAppCachedResponse(
572 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
574 EXPECT_TRUE(job
->is_delivering_appcache_response());
577 // Completion is async.
580 void VerifyDeliverSmallAppCachedResponse() {
581 EXPECT_TRUE(request_
->status().is_success());
582 EXPECT_TRUE(CompareHttpResponseInfos(
583 write_info_buffer_
->http_info
.get(),
584 &url_request_delegate_
->received_info_
));
585 EXPECT_EQ(5, url_request_delegate_
->amount_received_
);
586 EXPECT_EQ(0, memcmp(kHttpBasicBody
,
587 url_request_delegate_
->received_data_
->data(),
588 strlen(kHttpBasicBody
)));
592 // DeliverLargeAppCachedResponse --------------------------------------
593 // "Large" enough to require multiple calls to request->Read to complete.
595 void DeliverLargeAppCachedResponse() {
596 // This test has several async steps.
597 // 1. Write a large response to response storage.
598 // 2. Use net::URLRequest to retrieve it.
599 // 3. Verify we received what we expected to receive.
601 PushNextTask(base::Bind(
602 &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse
,
603 base::Unretained(this)));
604 PushNextTask(base::Bind(
605 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
606 base::Unretained(this), true));
608 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
609 written_response_id_
= writer_
->response_id();
610 WriteLargeResponse();
614 void WriteLargeResponse() {
616 static const char kHttpHeaders
[] =
617 "HTTP/1.0 200 OK\0Content-Length: 3072\0\0";
618 scoped_refptr
<IOBuffer
> body(new IOBuffer(kBlockSize
* 3));
619 char* p
= body
->data();
620 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
621 FillData(i
+ 1, p
, kBlockSize
);
622 std::string
raw_headers(kHttpHeaders
, arraysize(kHttpHeaders
));
624 MakeHttpResponseInfo(raw_headers
), body
.get(), kBlockSize
* 3);
627 void VerifyDeliverLargeAppCachedResponse() {
628 EXPECT_TRUE(request_
->status().is_success());
629 EXPECT_TRUE(CompareHttpResponseInfos(
630 write_info_buffer_
->http_info
.get(),
631 &url_request_delegate_
->received_info_
));
632 EXPECT_EQ(3072, url_request_delegate_
->amount_received_
);
633 char* p
= url_request_delegate_
->received_data_
->data();
634 for (int i
= 0; i
< 3; ++i
, p
+= kBlockSize
)
635 EXPECT_TRUE(CheckData(i
+ 1, p
, kBlockSize
));
639 // DeliverPartialResponse --------------------------------------
641 void DeliverPartialResponse() {
642 // This test has several async steps.
643 // 1. Write a small response to response storage.
644 // 2. Use net::URLRequest to retrieve it a subset using a range request
645 // 3. Verify we received what we expected to receive.
646 PushNextTask(base::Bind(
647 &AppCacheURLRequestJobTest::VerifyDeliverPartialResponse
,
648 base::Unretained(this)));
649 PushNextTask(base::Bind(
650 &AppCacheURLRequestJobTest::MakeRangeRequest
, base::Unretained(this)));
651 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
652 written_response_id_
= writer_
->response_id();
653 WriteBasicResponse();
657 void MakeRangeRequest() {
658 AppCacheStorage
* storage
= service_
->storage();
659 request_
= empty_context_
.CreateRequest(GURL("http://blah/"),
660 net::DEFAULT_PRIORITY
,
661 url_request_delegate_
.get(),
664 // Request a range, the 3 middle chars out of 'Hello'
665 net::HttpRequestHeaders extra_headers
;
666 extra_headers
.SetHeader("Range", "bytes= 1-3");
667 request_
->SetExtraRequestHeaders(extra_headers
);
669 // Create job with orders to deliver an appcached entry.
670 scoped_refptr
<AppCacheURLRequestJob
> job(new AppCacheURLRequestJob(
671 request_
.get(), NULL
, storage
, NULL
, false));
672 job
->DeliverAppCachedResponse(
674 AppCacheEntry(AppCacheEntry::EXPLICIT
, written_response_id_
),
676 EXPECT_TRUE(job
->is_delivering_appcache_response());
678 // Start the request.
679 EXPECT_FALSE(job
->has_been_started());
680 mock_factory_job_
= job
.get();
682 EXPECT_FALSE(mock_factory_job_
);
683 EXPECT_TRUE(job
->has_been_started());
684 // Completion is async.
687 void VerifyDeliverPartialResponse() {
688 EXPECT_TRUE(request_
->status().is_success());
689 EXPECT_EQ(3, url_request_delegate_
->amount_received_
);
690 EXPECT_EQ(0, memcmp(kHttpBasicBody
+ 1,
691 url_request_delegate_
->received_data_
->data(),
693 net::HttpResponseHeaders
* headers
=
694 url_request_delegate_
->received_info_
.headers
.get();
695 EXPECT_EQ(206, headers
->response_code());
696 EXPECT_EQ(3, headers
->GetContentLength());
697 int64 range_start
, range_end
, object_size
;
699 headers
->GetContentRange(&range_start
, &range_end
, &object_size
));
700 EXPECT_EQ(1, range_start
);
701 EXPECT_EQ(3, range_end
);
702 EXPECT_EQ(5, object_size
);
706 // CancelRequest --------------------------------------
708 void CancelRequest() {
709 // This test has several async steps.
710 // 1. Write a large response to response storage.
711 // 2. Use net::URLRequest to retrieve it.
712 // 3. Cancel the request after data starts coming in.
714 PushNextTask(base::Bind(
715 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
716 PushNextTask(base::Bind(
717 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
718 base::Unretained(this), true));
720 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
721 written_response_id_
= writer_
->response_id();
722 WriteLargeResponse();
724 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
725 url_request_delegate_
->kill_with_io_pending_
= false;
729 void VerifyCancel() {
730 EXPECT_EQ(net::URLRequestStatus::CANCELED
,
731 request_
->status().status());
735 // CancelRequestWithIOPending --------------------------------------
737 void CancelRequestWithIOPending() {
738 // This test has several async steps.
739 // 1. Write a large response to response storage.
740 // 2. Use net::URLRequest to retrieve it.
741 // 3. Cancel the request after data starts coming in.
743 PushNextTask(base::Bind(
744 &AppCacheURLRequestJobTest::VerifyCancel
, base::Unretained(this)));
745 PushNextTask(base::Bind(
746 &AppCacheURLRequestJobTest::RequestAppCachedResource
,
747 base::Unretained(this), true));
749 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
750 written_response_id_
= writer_
->response_id();
751 WriteLargeResponse();
753 url_request_delegate_
->kill_after_amount_received_
= kBlockSize
;
754 url_request_delegate_
->kill_with_io_pending_
= true;
759 // Data members --------------------------------------------------------
761 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
762 scoped_ptr
<MockStorageDelegate
> storage_delegate_
;
763 scoped_ptr
<MockAppCacheService
> service_
;
764 std::stack
<std::pair
<base::Closure
, bool> > task_stack_
;
766 scoped_ptr
<AppCacheResponseReader
> reader_
;
767 scoped_refptr
<HttpResponseInfoIOBuffer
> read_info_buffer_
;
768 scoped_refptr
<IOBuffer
> read_buffer_
;
769 int expected_read_result_
;
770 int reader_deletion_count_down_
;
772 int64 written_response_id_
;
773 scoped_ptr
<AppCacheResponseWriter
> writer_
;
774 scoped_refptr
<HttpResponseInfoIOBuffer
> write_info_buffer_
;
775 scoped_refptr
<IOBuffer
> write_buffer_
;
776 int expected_write_result_
;
777 int writer_deletion_count_down_
;
779 net::URLRequest::ProtocolFactory
* orig_http_factory_
;
780 net::URLRequestContext empty_context_
;
781 scoped_ptr
<net::URLRequest
> request_
;
782 scoped_ptr
<MockURLRequestDelegate
> url_request_delegate_
;
784 static scoped_ptr
<base::Thread
> io_thread_
;
785 static AppCacheURLRequestJob
* mock_factory_job_
;
789 scoped_ptr
<base::Thread
> AppCacheURLRequestJobTest::io_thread_
;
790 AppCacheURLRequestJob
* AppCacheURLRequestJobTest::mock_factory_job_
= NULL
;
792 TEST_F(AppCacheURLRequestJobTest
, Basic
) {
793 RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic
);
796 TEST_F(AppCacheURLRequestJobTest
, DeliveryOrders
) {
797 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders
);
800 TEST_F(AppCacheURLRequestJobTest
, DeliverNetworkResponse
) {
801 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse
);
804 TEST_F(AppCacheURLRequestJobTest
, DeliverErrorResponse
) {
805 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse
);
808 TEST_F(AppCacheURLRequestJobTest
, DeliverSmallAppCachedResponse
) {
809 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse
);
812 TEST_F(AppCacheURLRequestJobTest
, DeliverLargeAppCachedResponse
) {
813 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse
);
816 TEST_F(AppCacheURLRequestJobTest
, DeliverPartialResponse
) {
817 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse
);
820 TEST_F(AppCacheURLRequestJobTest
, CancelRequest
) {
821 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest
);
824 TEST_F(AppCacheURLRequestJobTest
, CancelRequestWithIOPending
) {
825 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending
);
828 } // namespace content