Update V8 to version 4.6.55.
[chromium-blink-merge.git] / content / browser / appcache / appcache_url_request_job_unittest.cc
blob0e27295a0ebfdcde5cd853fd40b7beff557b82a7
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/location.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/pickle.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/threading/thread.h"
20 #include "content/browser/appcache/appcache_response.h"
21 #include "content/browser/appcache/appcache_url_request_job.h"
22 #include "content/browser/appcache/mock_appcache_service.h"
23 #include "net/base/io_buffer.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/request_priority.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/url_request/url_request.h"
28 #include "net/url_request/url_request_context.h"
29 #include "net/url_request/url_request_error_job.h"
30 #include "net/url_request/url_request_job_factory.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "url/gurl.h"
34 using net::IOBuffer;
35 using net::WrappedIOBuffer;
37 namespace content {
39 namespace {
41 const char kHttpBasicHeaders[] = "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
42 const char kHttpBasicBody[] = "Hello";
44 const int kNumBlocks = 4;
45 const int kBlockSize = 1024;
47 class MockURLRequestJobFactory : public net::URLRequestJobFactory {
48 public:
49 MockURLRequestJobFactory() : job_(NULL) {
52 ~MockURLRequestJobFactory() override { DCHECK(!job_); }
54 void SetJob(net::URLRequestJob* job) {
55 job_ = job;
58 bool has_job() const {
59 return job_ != NULL;
62 // net::URLRequestJobFactory implementation.
63 net::URLRequestJob* MaybeCreateJobWithProtocolHandler(
64 const std::string& scheme,
65 net::URLRequest* request,
66 net::NetworkDelegate* network_delegate) const override {
67 if (job_) {
68 net::URLRequestJob* temp = job_;
69 job_ = NULL;
70 return temp;
71 } else {
72 return new net::URLRequestErrorJob(request,
73 network_delegate,
74 net::ERR_INTERNET_DISCONNECTED);
78 net::URLRequestJob* MaybeInterceptRedirect(
79 net::URLRequest* request,
80 net::NetworkDelegate* network_delegate,
81 const GURL& location) const override {
82 return nullptr;
85 net::URLRequestJob* MaybeInterceptResponse(
86 net::URLRequest* request,
87 net::NetworkDelegate* network_delegate) const override {
88 return nullptr;
91 bool IsHandledProtocol(const std::string& scheme) const override {
92 return scheme == "http";
95 bool IsHandledURL(const GURL& url) const override {
96 return url.SchemeIs("http");
99 bool IsSafeRedirectTarget(const GURL& location) const override {
100 return false;
103 private:
104 mutable net::URLRequestJob* job_;
107 class AppCacheURLRequestJobTest : public testing::Test {
108 public:
110 // Test Harness -------------------------------------------------------------
111 // TODO(michaeln): share this test harness with AppCacheResponseTest
113 class MockStorageDelegate : public AppCacheStorage::Delegate {
114 public:
115 explicit MockStorageDelegate(AppCacheURLRequestJobTest* test)
116 : loaded_info_id_(0), test_(test) {
119 void OnResponseInfoLoaded(AppCacheResponseInfo* info,
120 int64 response_id) override {
121 loaded_info_ = info;
122 loaded_info_id_ = response_id;
123 test_->ScheduleNextTask();
126 scoped_refptr<AppCacheResponseInfo> loaded_info_;
127 int64 loaded_info_id_;
128 AppCacheURLRequestJobTest* test_;
131 class MockURLRequestDelegate : public net::URLRequest::Delegate {
132 public:
133 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest* test)
134 : test_(test),
135 received_data_(new net::IOBuffer(kNumBlocks * kBlockSize)),
136 did_receive_headers_(false), amount_received_(0),
137 kill_after_amount_received_(0), kill_with_io_pending_(false) {
140 void OnResponseStarted(net::URLRequest* request) override {
141 amount_received_ = 0;
142 did_receive_headers_ = false;
143 if (request->status().is_success()) {
144 EXPECT_TRUE(request->response_headers());
145 did_receive_headers_ = true;
146 received_info_ = request->response_info();
147 ReadSome(request);
148 } else {
149 RequestComplete();
153 void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
154 if (bytes_read > 0) {
155 amount_received_ += bytes_read;
157 if (kill_after_amount_received_ && !kill_with_io_pending_) {
158 if (amount_received_ >= kill_after_amount_received_) {
159 request->Cancel();
160 return;
164 ReadSome(request);
166 if (kill_after_amount_received_ && kill_with_io_pending_) {
167 if (amount_received_ >= kill_after_amount_received_) {
168 request->Cancel();
169 return;
172 } else {
173 RequestComplete();
177 void ReadSome(net::URLRequest* request) {
178 DCHECK(amount_received_ + kBlockSize <= kNumBlocks * kBlockSize);
179 scoped_refptr<IOBuffer> wrapped_buffer(
180 new net::WrappedIOBuffer(received_data_->data() + amount_received_));
181 int bytes_read = 0;
182 EXPECT_FALSE(
183 request->Read(wrapped_buffer.get(), kBlockSize, &bytes_read));
184 EXPECT_EQ(0, bytes_read);
187 void RequestComplete() {
188 test_->ScheduleNextTask();
191 AppCacheURLRequestJobTest* test_;
192 net::HttpResponseInfo received_info_;
193 scoped_refptr<net::IOBuffer> received_data_;
194 bool did_receive_headers_;
195 int amount_received_;
196 int kill_after_amount_received_;
197 bool kill_with_io_pending_;
200 // Helper callback to run a test on our io_thread. The io_thread is spun up
201 // once and reused for all tests.
202 template <class Method>
203 void MethodWrapper(Method method) {
204 SetUpTest();
205 (this->*method)();
208 static void SetUpTestCase() {
209 io_thread_.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
210 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
211 io_thread_->StartWithOptions(options);
214 static void TearDownTestCase() {
215 io_thread_.reset(NULL);
218 AppCacheURLRequestJobTest() {}
220 template <class Method>
221 void RunTestOnIOThread(Method method) {
222 test_finished_event_ .reset(new base::WaitableEvent(false, false));
223 io_thread_->task_runner()->PostTask(
224 FROM_HERE, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper<Method>,
225 base::Unretained(this), method));
226 test_finished_event_->Wait();
229 void SetUpTest() {
230 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
231 DCHECK(task_stack_.empty());
233 storage_delegate_.reset(new MockStorageDelegate(this));
234 service_.reset(new MockAppCacheService());
235 expected_read_result_ = 0;
236 expected_write_result_ = 0;
237 written_response_id_ = 0;
238 reader_deletion_count_down_ = 0;
239 writer_deletion_count_down_ = 0;
241 url_request_delegate_.reset(new MockURLRequestDelegate(this));
242 job_factory_.reset(new MockURLRequestJobFactory());
243 empty_context_.reset(new net::URLRequestContext());
244 empty_context_->set_job_factory(job_factory_.get());
247 void TearDownTest() {
248 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
249 request_.reset();
251 while (!task_stack_.empty())
252 task_stack_.pop();
254 reader_.reset();
255 read_buffer_ = NULL;
256 read_info_buffer_ = NULL;
257 writer_.reset();
258 write_buffer_ = NULL;
259 write_info_buffer_ = NULL;
260 storage_delegate_.reset();
261 service_.reset();
263 DCHECK(!job_factory_->has_job());
264 empty_context_.reset();
265 job_factory_.reset();
266 url_request_delegate_.reset();
269 void TestFinished() {
270 // We unwind the stack prior to finishing up to let stack
271 // based objects get deleted.
272 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
273 base::ThreadTaskRunnerHandle::Get()->PostTask(
274 FROM_HERE, base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound,
275 base::Unretained(this)));
278 void TestFinishedUnwound() {
279 TearDownTest();
280 test_finished_event_->Signal();
283 void PushNextTask(const base::Closure& task) {
284 task_stack_.push(std::pair<base::Closure, bool>(task, false));
287 void PushNextTaskAsImmediate(const base::Closure& task) {
288 task_stack_.push(std::pair<base::Closure, bool>(task, true));
291 void ScheduleNextTask() {
292 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
293 if (task_stack_.empty()) {
294 TestFinished();
295 return;
297 base::Closure task =task_stack_.top().first;
298 bool immediate = task_stack_.top().second;
299 task_stack_.pop();
300 if (immediate)
301 task.Run();
302 else
303 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
306 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
308 void WriteBasicResponse() {
309 scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBasicBody));
310 std::string raw_headers(kHttpBasicHeaders, arraysize(kHttpBasicHeaders));
311 WriteResponse(
312 MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBasicBody));
315 void WriteResponse(net::HttpResponseInfo* head,
316 IOBuffer* body, int body_len) {
317 DCHECK(body);
318 scoped_refptr<IOBuffer> body_ref(body);
319 PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody,
320 base::Unretained(this), body_ref, body_len));
321 WriteResponseHead(head);
324 void WriteResponseHead(net::HttpResponseInfo* head) {
325 EXPECT_FALSE(writer_->IsWritePending());
326 expected_write_result_ = GetHttpResponseInfoSize(head);
327 write_info_buffer_ = new HttpResponseInfoIOBuffer(head);
328 writer_->WriteInfo(
329 write_info_buffer_.get(),
330 base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete,
331 base::Unretained(this)));
334 void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
335 EXPECT_FALSE(writer_->IsWritePending());
336 write_buffer_ = io_buffer;
337 expected_write_result_ = buf_len;
338 writer_->WriteData(write_buffer_.get(),
339 buf_len,
340 base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete,
341 base::Unretained(this)));
344 void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
345 EXPECT_FALSE(reader_->IsReadPending());
346 read_buffer_ = io_buffer;
347 expected_read_result_ = buf_len;
348 reader_->ReadData(read_buffer_.get(),
349 buf_len,
350 base::Bind(&AppCacheURLRequestJobTest::OnReadComplete,
351 base::Unretained(this)));
354 // AppCacheResponseReader / Writer completion callbacks
356 void OnWriteInfoComplete(int result) {
357 EXPECT_FALSE(writer_->IsWritePending());
358 EXPECT_EQ(expected_write_result_, result);
359 ScheduleNextTask();
362 void OnWriteComplete(int result) {
363 EXPECT_FALSE(writer_->IsWritePending());
364 EXPECT_EQ(expected_write_result_, result);
365 ScheduleNextTask();
368 void OnReadInfoComplete(int result) {
369 EXPECT_FALSE(reader_->IsReadPending());
370 EXPECT_EQ(expected_read_result_, result);
371 ScheduleNextTask();
374 void OnReadComplete(int result) {
375 EXPECT_FALSE(reader_->IsReadPending());
376 EXPECT_EQ(expected_read_result_, result);
377 ScheduleNextTask();
380 // Helpers to work with HttpResponseInfo objects
382 net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
383 net::HttpResponseInfo* info = new net::HttpResponseInfo;
384 info->request_time = base::Time::Now();
385 info->response_time = base::Time::Now();
386 info->was_cached = false;
387 info->headers = new net::HttpResponseHeaders(raw_headers);
388 return info;
391 int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
392 base::Pickle pickle;
393 return PickleHttpResonseInfo(&pickle, info);
396 bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
397 const net::HttpResponseInfo* info2) {
398 base::Pickle pickle1;
399 base::Pickle pickle2;
400 PickleHttpResonseInfo(&pickle1, info1);
401 PickleHttpResonseInfo(&pickle2, info2);
402 return (pickle1.size() == pickle2.size()) &&
403 (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
406 int PickleHttpResonseInfo(base::Pickle* pickle,
407 const net::HttpResponseInfo* info) {
408 const bool kSkipTransientHeaders = true;
409 const bool kTruncated = false;
410 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
411 return pickle->size();
414 // Helpers to fill and verify blocks of memory with a value
416 void FillData(char value, char* data, int data_len) {
417 memset(data, value, data_len);
420 bool CheckData(char value, const char* data, int data_len) {
421 for (int i = 0; i < data_len; ++i, ++data) {
422 if (*data != value)
423 return false;
425 return true;
428 // Individual Tests ---------------------------------------------------------
429 // Some of the individual tests involve multiple async steps. Each test
430 // is delineated with a section header.
432 // Basic -------------------------------------------------------------------
433 void Basic() {
434 AppCacheStorage* storage = service_->storage();
435 scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
436 GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL));
437 scoped_refptr<AppCacheURLRequestJob> job;
439 // Create an instance and see that it looks as expected.
441 job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
442 EXPECT_TRUE(job->is_waiting());
443 EXPECT_FALSE(job->is_delivering_appcache_response());
444 EXPECT_FALSE(job->is_delivering_network_response());
445 EXPECT_FALSE(job->is_delivering_error_response());
446 EXPECT_FALSE(job->has_been_started());
447 EXPECT_FALSE(job->has_been_killed());
448 EXPECT_EQ(GURL(), job->manifest_url());
449 EXPECT_EQ(kAppCacheNoCacheId, job->cache_id());
450 EXPECT_FALSE(job->entry().has_response_id());
452 TestFinished();
455 // DeliveryOrders -----------------------------------------------------
456 void DeliveryOrders() {
457 AppCacheStorage* storage = service_->storage();
458 scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
459 GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL));
460 scoped_refptr<AppCacheURLRequestJob> job;
462 // Create an instance, give it a delivery order and see that
463 // it looks as expected.
465 job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
466 job->DeliverErrorResponse();
467 EXPECT_TRUE(job->is_delivering_error_response());
468 EXPECT_FALSE(job->has_been_started());
470 job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
471 job->DeliverNetworkResponse();
472 EXPECT_TRUE(job->is_delivering_network_response());
473 EXPECT_FALSE(job->has_been_started());
475 job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
476 const GURL kManifestUrl("http://blah/");
477 const int64 kCacheId(1);
478 const int64 kGroupId(1);
479 const AppCacheEntry kEntry(AppCacheEntry::EXPLICIT, 1);
480 job->DeliverAppCachedResponse(kManifestUrl, kCacheId, kGroupId,
481 kEntry, false);
482 EXPECT_FALSE(job->is_waiting());
483 EXPECT_TRUE(job->is_delivering_appcache_response());
484 EXPECT_FALSE(job->has_been_started());
485 EXPECT_EQ(kManifestUrl, job->manifest_url());
486 EXPECT_EQ(kCacheId, job->cache_id());
487 EXPECT_EQ(kGroupId, job->group_id());
488 EXPECT_EQ(kEntry.types(), job->entry().types());
489 EXPECT_EQ(kEntry.response_id(), job->entry().response_id());
491 TestFinished();
494 // DeliverNetworkResponse --------------------------------------------------
496 void DeliverNetworkResponse() {
497 // This test has async steps.
498 PushNextTask(
499 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse,
500 base::Unretained(this)));
502 AppCacheStorage* storage = service_->storage();
503 request_ = empty_context_->CreateRequest(GURL("http://blah/"),
504 net::DEFAULT_PRIORITY,
505 url_request_delegate_.get());
507 // Setup to create an AppCacheURLRequestJob with orders to deliver
508 // a network response.
509 AppCacheURLRequestJob* mock_job = new AppCacheURLRequestJob(
510 request_.get(), NULL, storage, NULL, false);
511 job_factory_->SetJob(mock_job);
512 mock_job->DeliverNetworkResponse();
513 EXPECT_TRUE(mock_job->is_delivering_network_response());
514 EXPECT_FALSE(mock_job->has_been_started());
516 // Start the request.
517 request_->Start();
519 // The job should have been picked up.
520 EXPECT_FALSE(job_factory_->has_job());
521 // Completion is async.
524 void VerifyDeliverNetworkResponse() {
525 EXPECT_EQ(request_->status().error(),
526 net::ERR_INTERNET_DISCONNECTED);
527 TestFinished();
530 // DeliverErrorResponse --------------------------------------------------
532 void DeliverErrorResponse() {
533 // This test has async steps.
534 PushNextTask(
535 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse,
536 base::Unretained(this)));
538 AppCacheStorage* storage = service_->storage();
539 request_ = empty_context_->CreateRequest(GURL("http://blah/"),
540 net::DEFAULT_PRIORITY,
541 url_request_delegate_.get());
543 // Setup to create an AppCacheURLRequestJob with orders to deliver
544 // a network response.
545 AppCacheURLRequestJob* mock_job = new AppCacheURLRequestJob(
546 request_.get(), NULL, storage, NULL, false);
547 job_factory_->SetJob(mock_job);
548 mock_job->DeliverErrorResponse();
549 EXPECT_TRUE(mock_job->is_delivering_error_response());
550 EXPECT_FALSE(mock_job->has_been_started());
552 // Start the request.
553 request_->Start();
555 // The job should have been picked up.
556 EXPECT_FALSE(job_factory_->has_job());
557 // Completion is async.
560 void VerifyDeliverErrorResponse() {
561 EXPECT_EQ(request_->status().error(), net::ERR_FAILED);
562 TestFinished();
565 // DeliverSmallAppCachedResponse --------------------------------------
566 // "Small" being small enough to read completely in a single
567 // request->Read call.
569 void DeliverSmallAppCachedResponse() {
570 // This test has several async steps.
571 // 1. Write a small response to response storage.
572 // 2. Use net::URLRequest to retrieve it.
573 // 3. Verify we received what we expected to receive.
575 PushNextTask(base::Bind(
576 &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse,
577 base::Unretained(this)));
578 PushNextTask(
579 base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource,
580 base::Unretained(this), false));
582 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
583 written_response_id_ = writer_->response_id();
584 WriteBasicResponse();
585 // Continues async
588 void RequestAppCachedResource(bool start_after_delivery_orders) {
589 AppCacheStorage* storage = service_->storage();
590 request_ = empty_context_->CreateRequest(GURL("http://blah/"),
591 net::DEFAULT_PRIORITY,
592 url_request_delegate_.get());
594 // Setup to create an AppCacheURLRequestJob with orders to deliver
595 // a network response.
596 scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob(
597 request_.get(), NULL, storage, NULL, false));
599 if (start_after_delivery_orders) {
600 job->DeliverAppCachedResponse(
601 GURL(), 0, 111,
602 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
603 false);
604 EXPECT_TRUE(job->is_delivering_appcache_response());
607 // Start the request.
608 EXPECT_FALSE(job->has_been_started());
609 job_factory_->SetJob(job.get());
610 request_->Start();
611 EXPECT_FALSE(job_factory_->has_job());
612 EXPECT_TRUE(job->has_been_started());
614 if (!start_after_delivery_orders) {
615 job->DeliverAppCachedResponse(
616 GURL(), 0, 111,
617 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
618 false);
619 EXPECT_TRUE(job->is_delivering_appcache_response());
622 // Completion is async.
625 void VerifyDeliverSmallAppCachedResponse() {
626 EXPECT_TRUE(request_->status().is_success());
627 EXPECT_TRUE(CompareHttpResponseInfos(
628 write_info_buffer_->http_info.get(),
629 &url_request_delegate_->received_info_));
630 EXPECT_EQ(5, url_request_delegate_->amount_received_);
631 EXPECT_EQ(0, memcmp(kHttpBasicBody,
632 url_request_delegate_->received_data_->data(),
633 strlen(kHttpBasicBody)));
634 TestFinished();
637 // DeliverLargeAppCachedResponse --------------------------------------
638 // "Large" enough to require multiple calls to request->Read to complete.
640 void DeliverLargeAppCachedResponse() {
641 // This test has several async steps.
642 // 1. Write a large response to response storage.
643 // 2. Use net::URLRequest to retrieve it.
644 // 3. Verify we received what we expected to receive.
646 PushNextTask(base::Bind(
647 &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse,
648 base::Unretained(this)));
649 PushNextTask(base::Bind(
650 &AppCacheURLRequestJobTest::RequestAppCachedResource,
651 base::Unretained(this), true));
653 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
654 written_response_id_ = writer_->response_id();
655 WriteLargeResponse();
656 // Continues async
659 void WriteLargeResponse() {
660 // 3, 1k blocks
661 static const char kHttpHeaders[] =
662 "HTTP/1.0 200 OK\0Content-Length: 3072\0\0";
663 scoped_refptr<IOBuffer> body(new IOBuffer(kBlockSize * 3));
664 char* p = body->data();
665 for (int i = 0; i < 3; ++i, p += kBlockSize)
666 FillData(i + 1, p, kBlockSize);
667 std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
668 WriteResponse(
669 MakeHttpResponseInfo(raw_headers), body.get(), kBlockSize * 3);
672 void VerifyDeliverLargeAppCachedResponse() {
673 EXPECT_TRUE(request_->status().is_success());
674 EXPECT_TRUE(CompareHttpResponseInfos(
675 write_info_buffer_->http_info.get(),
676 &url_request_delegate_->received_info_));
677 EXPECT_EQ(3072, url_request_delegate_->amount_received_);
678 char* p = url_request_delegate_->received_data_->data();
679 for (int i = 0; i < 3; ++i, p += kBlockSize)
680 EXPECT_TRUE(CheckData(i + 1, p, kBlockSize));
681 TestFinished();
684 // DeliverPartialResponse --------------------------------------
686 void DeliverPartialResponse() {
687 // This test has several async steps.
688 // 1. Write a small response to response storage.
689 // 2. Use net::URLRequest to retrieve it a subset using a range request
690 // 3. Verify we received what we expected to receive.
691 PushNextTask(base::Bind(
692 &AppCacheURLRequestJobTest::VerifyDeliverPartialResponse,
693 base::Unretained(this)));
694 PushNextTask(base::Bind(
695 &AppCacheURLRequestJobTest::MakeRangeRequest, base::Unretained(this)));
696 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
697 written_response_id_ = writer_->response_id();
698 WriteBasicResponse();
699 // Continues async
702 void MakeRangeRequest() {
703 AppCacheStorage* storage = service_->storage();
704 request_ = empty_context_->CreateRequest(GURL("http://blah/"),
705 net::DEFAULT_PRIORITY,
706 url_request_delegate_.get());
708 // Request a range, the 3 middle chars out of 'Hello'
709 net::HttpRequestHeaders extra_headers;
710 extra_headers.SetHeader("Range", "bytes= 1-3");
711 request_->SetExtraRequestHeaders(extra_headers);
713 // Create job with orders to deliver an appcached entry.
714 scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob(
715 request_.get(), NULL, storage, NULL, false));
716 job->DeliverAppCachedResponse(
717 GURL(), 0, 111,
718 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
719 false);
720 EXPECT_TRUE(job->is_delivering_appcache_response());
722 // Start the request.
723 EXPECT_FALSE(job->has_been_started());
724 job_factory_->SetJob(job.get());
725 request_->Start();
726 EXPECT_FALSE(job_factory_->has_job());
727 EXPECT_TRUE(job->has_been_started());
728 // Completion is async.
731 void VerifyDeliverPartialResponse() {
732 EXPECT_TRUE(request_->status().is_success());
733 EXPECT_EQ(3, url_request_delegate_->amount_received_);
734 EXPECT_EQ(0, memcmp(kHttpBasicBody + 1,
735 url_request_delegate_->received_data_->data(),
736 3));
737 net::HttpResponseHeaders* headers =
738 url_request_delegate_->received_info_.headers.get();
739 EXPECT_EQ(206, headers->response_code());
740 EXPECT_EQ(3, headers->GetContentLength());
741 int64 range_start, range_end, object_size;
742 EXPECT_TRUE(
743 headers->GetContentRange(&range_start, &range_end, &object_size));
744 EXPECT_EQ(1, range_start);
745 EXPECT_EQ(3, range_end);
746 EXPECT_EQ(5, object_size);
747 TestFinished();
750 // CancelRequest --------------------------------------
752 void CancelRequest() {
753 // This test has several async steps.
754 // 1. Write a large response to response storage.
755 // 2. Use net::URLRequest to retrieve it.
756 // 3. Cancel the request after data starts coming in.
758 PushNextTask(base::Bind(
759 &AppCacheURLRequestJobTest::VerifyCancel, base::Unretained(this)));
760 PushNextTask(base::Bind(
761 &AppCacheURLRequestJobTest::RequestAppCachedResource,
762 base::Unretained(this), true));
764 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
765 written_response_id_ = writer_->response_id();
766 WriteLargeResponse();
768 url_request_delegate_->kill_after_amount_received_ = kBlockSize;
769 url_request_delegate_->kill_with_io_pending_ = false;
770 // Continues async
773 void VerifyCancel() {
774 EXPECT_EQ(net::URLRequestStatus::CANCELED,
775 request_->status().status());
776 TestFinished();
779 // CancelRequestWithIOPending --------------------------------------
781 void CancelRequestWithIOPending() {
782 // This test has several async steps.
783 // 1. Write a large response to response storage.
784 // 2. Use net::URLRequest to retrieve it.
785 // 3. Cancel the request after data starts coming in.
787 PushNextTask(base::Bind(
788 &AppCacheURLRequestJobTest::VerifyCancel, base::Unretained(this)));
789 PushNextTask(base::Bind(
790 &AppCacheURLRequestJobTest::RequestAppCachedResource,
791 base::Unretained(this), true));
793 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
794 written_response_id_ = writer_->response_id();
795 WriteLargeResponse();
797 url_request_delegate_->kill_after_amount_received_ = kBlockSize;
798 url_request_delegate_->kill_with_io_pending_ = true;
799 // Continues async
803 // Data members --------------------------------------------------------
805 scoped_ptr<base::WaitableEvent> test_finished_event_;
806 scoped_ptr<MockStorageDelegate> storage_delegate_;
807 scoped_ptr<MockAppCacheService> service_;
808 std::stack<std::pair<base::Closure, bool> > task_stack_;
810 scoped_ptr<AppCacheResponseReader> reader_;
811 scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_;
812 scoped_refptr<IOBuffer> read_buffer_;
813 int expected_read_result_;
814 int reader_deletion_count_down_;
816 int64 written_response_id_;
817 scoped_ptr<AppCacheResponseWriter> writer_;
818 scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
819 scoped_refptr<IOBuffer> write_buffer_;
820 int expected_write_result_;
821 int writer_deletion_count_down_;
823 scoped_ptr<MockURLRequestJobFactory> job_factory_;
824 scoped_ptr<net::URLRequestContext> empty_context_;
825 scoped_ptr<net::URLRequest> request_;
826 scoped_ptr<MockURLRequestDelegate> url_request_delegate_;
828 static scoped_ptr<base::Thread> io_thread_;
831 // static
832 scoped_ptr<base::Thread> AppCacheURLRequestJobTest::io_thread_;
834 TEST_F(AppCacheURLRequestJobTest, Basic) {
835 RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic);
838 TEST_F(AppCacheURLRequestJobTest, DeliveryOrders) {
839 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders);
842 TEST_F(AppCacheURLRequestJobTest, DeliverNetworkResponse) {
843 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse);
846 TEST_F(AppCacheURLRequestJobTest, DeliverErrorResponse) {
847 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse);
850 TEST_F(AppCacheURLRequestJobTest, DeliverSmallAppCachedResponse) {
851 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse);
854 TEST_F(AppCacheURLRequestJobTest, DeliverLargeAppCachedResponse) {
855 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse);
858 TEST_F(AppCacheURLRequestJobTest, DeliverPartialResponse) {
859 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse);
862 TEST_F(AppCacheURLRequestJobTest, CancelRequest) {
863 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest);
866 TEST_F(AppCacheURLRequestJobTest, CancelRequestWithIOPending) {
867 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending);
870 } // namespace
872 } // namespace content