Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / browser / appcache / appcache_url_request_job_unittest.cc
blob31518fb5502dcca7e43b696caa9472e9d4c1a39d
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 virtual ~MockURLRequestJobFactory() {
50 DCHECK(!job_);
53 void SetJob(net::URLRequestJob* job) {
54 job_ = job;
57 bool has_job() const {
58 return job_ != NULL;
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 {
66 if (job_) {
67 net::URLRequestJob* temp = job_;
68 job_ = NULL;
69 return temp;
70 } else {
71 return new net::URLRequestErrorJob(request,
72 network_delegate,
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 {
86 return false;
89 private:
90 mutable net::URLRequestJob* job_;
93 class AppCacheURLRequestJobTest : public testing::Test {
94 public:
96 // Test Harness -------------------------------------------------------------
97 // TODO(michaeln): share this test harness with AppCacheResponseTest
99 class MockStorageDelegate : public AppCacheStorage::Delegate {
100 public:
101 explicit MockStorageDelegate(AppCacheURLRequestJobTest* test)
102 : loaded_info_id_(0), test_(test) {
105 virtual void OnResponseInfoLoaded(AppCacheResponseInfo* info,
106 int64 response_id) OVERRIDE {
107 loaded_info_ = info;
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 {
118 public:
119 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest* test)
120 : test_(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();
133 ReadSome(request);
134 } else {
135 RequestComplete();
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_) {
146 request->Cancel();
147 return;
151 ReadSome(request);
153 if (kill_after_amount_received_ && kill_with_io_pending_) {
154 if (amount_received_ >= kill_after_amount_received_) {
155 request->Cancel();
156 return;
159 } else {
160 RequestComplete();
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_));
168 int bytes_read = 0;
169 EXPECT_FALSE(
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) {
191 SetUpTest();
192 (this->*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();
216 void SetUpTest() {
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());
236 request_.reset();
238 while (!task_stack_.empty())
239 task_stack_.pop();
241 reader_.reset();
242 read_buffer_ = NULL;
243 read_info_buffer_ = NULL;
244 writer_.reset();
245 write_buffer_ = NULL;
246 write_info_buffer_ = NULL;
247 storage_delegate_.reset();
248 service_.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(
261 FROM_HERE,
262 base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound,
263 base::Unretained(this)));
266 void TestFinishedUnwound() {
267 TearDownTest();
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()) {
282 TestFinished();
283 return;
285 base::Closure task =task_stack_.top().first;
286 bool immediate = task_stack_.top().second;
287 task_stack_.pop();
288 if (immediate)
289 task.Run();
290 else
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));
299 WriteResponse(
300 MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBasicBody));
303 void WriteResponse(net::HttpResponseInfo* head,
304 IOBuffer* body, int body_len) {
305 DCHECK(body);
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);
316 writer_->WriteInfo(
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(),
327 buf_len,
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(),
337 buf_len,
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);
347 ScheduleNextTask();
350 void OnWriteComplete(int result) {
351 EXPECT_FALSE(writer_->IsWritePending());
352 EXPECT_EQ(expected_write_result_, result);
353 ScheduleNextTask();
356 void OnReadInfoComplete(int result) {
357 EXPECT_FALSE(reader_->IsReadPending());
358 EXPECT_EQ(expected_read_result_, result);
359 ScheduleNextTask();
362 void OnReadComplete(int result) {
363 EXPECT_FALSE(reader_->IsReadPending());
364 EXPECT_EQ(expected_read_result_, result);
365 ScheduleNextTask();
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);
376 return info;
379 int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
380 Pickle pickle;
381 return PickleHttpResonseInfo(&pickle, info);
384 bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
385 const net::HttpResponseInfo* info2) {
386 Pickle pickle1;
387 Pickle pickle2;
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) {
409 if (*data != value)
410 return false;
412 return true;
415 // Individual Tests ---------------------------------------------------------
416 // Some of the individual tests involve multiple async steps. Each test
417 // is delineated with a section header.
419 // Basic -------------------------------------------------------------------
420 void 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());
439 TestFinished();
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,
468 kEntry, false);
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());
478 TestFinished();
481 // DeliverNetworkResponse --------------------------------------------------
483 void DeliverNetworkResponse() {
484 // This test has async steps.
485 PushNextTask(
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(),
493 NULL);
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.
505 request_->Start();
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);
515 TestFinished();
518 // DeliverErrorResponse --------------------------------------------------
520 void DeliverErrorResponse() {
521 // This test has async steps.
522 PushNextTask(
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(),
530 NULL);
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.
542 request_->Start();
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);
551 TestFinished();
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)));
567 PushNextTask(
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();
574 // Continues async
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(),
582 NULL);
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(
591 GURL(), 0, 111,
592 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
593 false);
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());
600 request_->Start();
601 EXPECT_FALSE(job_factory_->has_job());
602 EXPECT_TRUE(job->has_been_started());
604 if (!start_after_delivery_orders) {
605 job->DeliverAppCachedResponse(
606 GURL(), 0, 111,
607 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
608 false);
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)));
624 TestFinished();
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();
646 // Continues async
649 void WriteLargeResponse() {
650 // 3, 1k blocks
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));
658 WriteResponse(
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));
671 TestFinished();
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();
689 // Continues async
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(),
697 NULL);
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(
708 GURL(), 0, 111,
709 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
710 false);
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());
716 request_->Start();
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(),
727 3));
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;
733 EXPECT_TRUE(
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);
738 TestFinished();
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;
761 // Continues async
764 void VerifyCancel() {
765 EXPECT_EQ(net::URLRequestStatus::CANCELED,
766 request_->status().status());
767 TestFinished();
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;
790 // Continues async
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_;
822 // static
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);
861 } // namespace
863 } // namespace content