Apply _RELATIVE relocations ahead of others.
[chromium-blink-merge.git] / content / browser / appcache / appcache_url_request_job_unittest.cc
blob08b0fc1f5e010317c7189ce1589eb9b4b538850f
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 <utility>
8 #include "base/bind.h"
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"
29 #include "url/gurl.h"
31 using net::IOBuffer;
32 using net::WrappedIOBuffer;
34 namespace content {
36 namespace {
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 {
45 public:
46 MockURLRequestJobFactory() : job_(NULL) {
49 ~MockURLRequestJobFactory() override { DCHECK(!job_); }
51 void SetJob(net::URLRequestJob* job) {
52 job_ = job;
55 bool has_job() const {
56 return job_ != NULL;
59 // net::URLRequestJobFactory implementation.
60 net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
61 const std::string& scheme,
62 net::URLRequest* request,
63 net::NetworkDelegate* network_delegate) const override {
64 if (job_) {
65 net::URLRequestJob* temp = job_;
66 job_ = NULL;
67 return temp;
68 } else {
69 return new net::URLRequestErrorJob(request,
70 network_delegate,
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 {
84 return false;
87 private:
88 mutable net::URLRequestJob* job_;
91 class AppCacheURLRequestJobTest : public testing::Test {
92 public:
94 // Test Harness -------------------------------------------------------------
95 // TODO(michaeln): share this test harness with AppCacheResponseTest
97 class MockStorageDelegate : public AppCacheStorage::Delegate {
98 public:
99 explicit MockStorageDelegate(AppCacheURLRequestJobTest* test)
100 : loaded_info_id_(0), test_(test) {
103 void OnResponseInfoLoaded(AppCacheResponseInfo* info,
104 int64 response_id) override {
105 loaded_info_ = info;
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 {
116 public:
117 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest* test)
118 : test_(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();
131 ReadSome(request);
132 } else {
133 RequestComplete();
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_) {
143 request->Cancel();
144 return;
148 ReadSome(request);
150 if (kill_after_amount_received_ && kill_with_io_pending_) {
151 if (amount_received_ >= kill_after_amount_received_) {
152 request->Cancel();
153 return;
156 } else {
157 RequestComplete();
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_));
165 int bytes_read = 0;
166 EXPECT_FALSE(
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) {
188 SetUpTest();
189 (this->*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();
213 void SetUpTest() {
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());
233 request_.reset();
235 while (!task_stack_.empty())
236 task_stack_.pop();
238 reader_.reset();
239 read_buffer_ = NULL;
240 read_info_buffer_ = NULL;
241 writer_.reset();
242 write_buffer_ = NULL;
243 write_info_buffer_ = NULL;
244 storage_delegate_.reset();
245 service_.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(
258 FROM_HERE,
259 base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound,
260 base::Unretained(this)));
263 void TestFinishedUnwound() {
264 TearDownTest();
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()) {
279 TestFinished();
280 return;
282 base::Closure task =task_stack_.top().first;
283 bool immediate = task_stack_.top().second;
284 task_stack_.pop();
285 if (immediate)
286 task.Run();
287 else
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));
296 WriteResponse(
297 MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBasicBody));
300 void WriteResponse(net::HttpResponseInfo* head,
301 IOBuffer* body, int body_len) {
302 DCHECK(body);
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);
313 writer_->WriteInfo(
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(),
324 buf_len,
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(),
334 buf_len,
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);
344 ScheduleNextTask();
347 void OnWriteComplete(int result) {
348 EXPECT_FALSE(writer_->IsWritePending());
349 EXPECT_EQ(expected_write_result_, result);
350 ScheduleNextTask();
353 void OnReadInfoComplete(int result) {
354 EXPECT_FALSE(reader_->IsReadPending());
355 EXPECT_EQ(expected_read_result_, result);
356 ScheduleNextTask();
359 void OnReadComplete(int result) {
360 EXPECT_FALSE(reader_->IsReadPending());
361 EXPECT_EQ(expected_read_result_, result);
362 ScheduleNextTask();
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);
373 return info;
376 int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
377 Pickle pickle;
378 return PickleHttpResonseInfo(&pickle, info);
381 bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
382 const net::HttpResponseInfo* info2) {
383 Pickle pickle1;
384 Pickle pickle2;
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) {
406 if (*data != value)
407 return false;
409 return true;
412 // Individual Tests ---------------------------------------------------------
413 // Some of the individual tests involve multiple async steps. Each test
414 // is delineated with a section header.
416 // Basic -------------------------------------------------------------------
417 void 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());
436 TestFinished();
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,
465 kEntry, false);
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());
475 TestFinished();
478 // DeliverNetworkResponse --------------------------------------------------
480 void DeliverNetworkResponse() {
481 // This test has async steps.
482 PushNextTask(
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(),
490 NULL);
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.
502 request_->Start();
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);
512 TestFinished();
515 // DeliverErrorResponse --------------------------------------------------
517 void DeliverErrorResponse() {
518 // This test has async steps.
519 PushNextTask(
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(),
527 NULL);
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.
539 request_->Start();
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);
548 TestFinished();
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)));
564 PushNextTask(
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();
571 // Continues async
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(),
579 NULL);
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(
588 GURL(), 0, 111,
589 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
590 false);
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());
597 request_->Start();
598 EXPECT_FALSE(job_factory_->has_job());
599 EXPECT_TRUE(job->has_been_started());
601 if (!start_after_delivery_orders) {
602 job->DeliverAppCachedResponse(
603 GURL(), 0, 111,
604 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
605 false);
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)));
621 TestFinished();
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();
643 // Continues async
646 void WriteLargeResponse() {
647 // 3, 1k blocks
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));
655 WriteResponse(
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));
668 TestFinished();
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();
686 // Continues async
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(),
694 NULL);
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(
705 GURL(), 0, 111,
706 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
707 false);
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());
713 request_->Start();
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(),
724 3));
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;
730 EXPECT_TRUE(
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);
735 TestFinished();
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;
758 // Continues async
761 void VerifyCancel() {
762 EXPECT_EQ(net::URLRequestStatus::CANCELED,
763 request_->status().status());
764 TestFinished();
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;
787 // Continues async
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_;
819 // static
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);
858 } // namespace
860 } // namespace content