ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / appcache / appcache_url_request_job_unittest.cc
blob8acc71c7c9c577a6ac5119004bce822e00b188dc
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 net::URLRequestJob* MaybeInterceptRedirect(
76 net::URLRequest* request,
77 net::NetworkDelegate* network_delegate,
78 const GURL& location) const override {
79 return nullptr;
82 net::URLRequestJob* MaybeInterceptResponse(
83 net::URLRequest* request,
84 net::NetworkDelegate* network_delegate) const override {
85 return nullptr;
88 bool IsHandledProtocol(const std::string& scheme) const override {
89 return scheme == "http";
92 bool IsHandledURL(const GURL& url) const override {
93 return url.SchemeIs("http");
96 bool IsSafeRedirectTarget(const GURL& location) const override {
97 return false;
100 private:
101 mutable net::URLRequestJob* job_;
104 class AppCacheURLRequestJobTest : public testing::Test {
105 public:
107 // Test Harness -------------------------------------------------------------
108 // TODO(michaeln): share this test harness with AppCacheResponseTest
110 class MockStorageDelegate : public AppCacheStorage::Delegate {
111 public:
112 explicit MockStorageDelegate(AppCacheURLRequestJobTest* test)
113 : loaded_info_id_(0), test_(test) {
116 void OnResponseInfoLoaded(AppCacheResponseInfo* info,
117 int64 response_id) override {
118 loaded_info_ = info;
119 loaded_info_id_ = response_id;
120 test_->ScheduleNextTask();
123 scoped_refptr<AppCacheResponseInfo> loaded_info_;
124 int64 loaded_info_id_;
125 AppCacheURLRequestJobTest* test_;
128 class MockURLRequestDelegate : public net::URLRequest::Delegate {
129 public:
130 explicit MockURLRequestDelegate(AppCacheURLRequestJobTest* test)
131 : test_(test),
132 received_data_(new net::IOBuffer(kNumBlocks * kBlockSize)),
133 did_receive_headers_(false), amount_received_(0),
134 kill_after_amount_received_(0), kill_with_io_pending_(false) {
137 void OnResponseStarted(net::URLRequest* request) override {
138 amount_received_ = 0;
139 did_receive_headers_ = false;
140 if (request->status().is_success()) {
141 EXPECT_TRUE(request->response_headers());
142 did_receive_headers_ = true;
143 received_info_ = request->response_info();
144 ReadSome(request);
145 } else {
146 RequestComplete();
150 void OnReadCompleted(net::URLRequest* request, int bytes_read) override {
151 if (bytes_read > 0) {
152 amount_received_ += bytes_read;
154 if (kill_after_amount_received_ && !kill_with_io_pending_) {
155 if (amount_received_ >= kill_after_amount_received_) {
156 request->Cancel();
157 return;
161 ReadSome(request);
163 if (kill_after_amount_received_ && kill_with_io_pending_) {
164 if (amount_received_ >= kill_after_amount_received_) {
165 request->Cancel();
166 return;
169 } else {
170 RequestComplete();
174 void ReadSome(net::URLRequest* request) {
175 DCHECK(amount_received_ + kBlockSize <= kNumBlocks * kBlockSize);
176 scoped_refptr<IOBuffer> wrapped_buffer(
177 new net::WrappedIOBuffer(received_data_->data() + amount_received_));
178 int bytes_read = 0;
179 EXPECT_FALSE(
180 request->Read(wrapped_buffer.get(), kBlockSize, &bytes_read));
181 EXPECT_EQ(0, bytes_read);
184 void RequestComplete() {
185 test_->ScheduleNextTask();
188 AppCacheURLRequestJobTest* test_;
189 net::HttpResponseInfo received_info_;
190 scoped_refptr<net::IOBuffer> received_data_;
191 bool did_receive_headers_;
192 int amount_received_;
193 int kill_after_amount_received_;
194 bool kill_with_io_pending_;
197 // Helper callback to run a test on our io_thread. The io_thread is spun up
198 // once and reused for all tests.
199 template <class Method>
200 void MethodWrapper(Method method) {
201 SetUpTest();
202 (this->*method)();
205 static void SetUpTestCase() {
206 io_thread_.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
207 base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
208 io_thread_->StartWithOptions(options);
211 static void TearDownTestCase() {
212 io_thread_.reset(NULL);
215 AppCacheURLRequestJobTest() {}
217 template <class Method>
218 void RunTestOnIOThread(Method method) {
219 test_finished_event_ .reset(new base::WaitableEvent(false, false));
220 io_thread_->message_loop()->PostTask(
221 FROM_HERE, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper<Method>,
222 base::Unretained(this), method));
223 test_finished_event_->Wait();
226 void SetUpTest() {
227 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
228 DCHECK(task_stack_.empty());
230 storage_delegate_.reset(new MockStorageDelegate(this));
231 service_.reset(new MockAppCacheService());
232 expected_read_result_ = 0;
233 expected_write_result_ = 0;
234 written_response_id_ = 0;
235 reader_deletion_count_down_ = 0;
236 writer_deletion_count_down_ = 0;
238 url_request_delegate_.reset(new MockURLRequestDelegate(this));
239 job_factory_.reset(new MockURLRequestJobFactory());
240 empty_context_.reset(new net::URLRequestContext());
241 empty_context_->set_job_factory(job_factory_.get());
244 void TearDownTest() {
245 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
246 request_.reset();
248 while (!task_stack_.empty())
249 task_stack_.pop();
251 reader_.reset();
252 read_buffer_ = NULL;
253 read_info_buffer_ = NULL;
254 writer_.reset();
255 write_buffer_ = NULL;
256 write_info_buffer_ = NULL;
257 storage_delegate_.reset();
258 service_.reset();
260 DCHECK(!job_factory_->has_job());
261 empty_context_.reset();
262 job_factory_.reset();
263 url_request_delegate_.reset();
266 void TestFinished() {
267 // We unwind the stack prior to finishing up to let stack
268 // based objects get deleted.
269 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
270 base::MessageLoop::current()->PostTask(
271 FROM_HERE,
272 base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound,
273 base::Unretained(this)));
276 void TestFinishedUnwound() {
277 TearDownTest();
278 test_finished_event_->Signal();
281 void PushNextTask(const base::Closure& task) {
282 task_stack_.push(std::pair<base::Closure, bool>(task, false));
285 void PushNextTaskAsImmediate(const base::Closure& task) {
286 task_stack_.push(std::pair<base::Closure, bool>(task, true));
289 void ScheduleNextTask() {
290 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
291 if (task_stack_.empty()) {
292 TestFinished();
293 return;
295 base::Closure task =task_stack_.top().first;
296 bool immediate = task_stack_.top().second;
297 task_stack_.pop();
298 if (immediate)
299 task.Run();
300 else
301 base::MessageLoop::current()->PostTask(FROM_HERE, task);
304 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
306 void WriteBasicResponse() {
307 scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBasicBody));
308 std::string raw_headers(kHttpBasicHeaders, arraysize(kHttpBasicHeaders));
309 WriteResponse(
310 MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBasicBody));
313 void WriteResponse(net::HttpResponseInfo* head,
314 IOBuffer* body, int body_len) {
315 DCHECK(body);
316 scoped_refptr<IOBuffer> body_ref(body);
317 PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody,
318 base::Unretained(this), body_ref, body_len));
319 WriteResponseHead(head);
322 void WriteResponseHead(net::HttpResponseInfo* head) {
323 EXPECT_FALSE(writer_->IsWritePending());
324 expected_write_result_ = GetHttpResponseInfoSize(head);
325 write_info_buffer_ = new HttpResponseInfoIOBuffer(head);
326 writer_->WriteInfo(
327 write_info_buffer_.get(),
328 base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete,
329 base::Unretained(this)));
332 void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
333 EXPECT_FALSE(writer_->IsWritePending());
334 write_buffer_ = io_buffer;
335 expected_write_result_ = buf_len;
336 writer_->WriteData(write_buffer_.get(),
337 buf_len,
338 base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete,
339 base::Unretained(this)));
342 void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
343 EXPECT_FALSE(reader_->IsReadPending());
344 read_buffer_ = io_buffer;
345 expected_read_result_ = buf_len;
346 reader_->ReadData(read_buffer_.get(),
347 buf_len,
348 base::Bind(&AppCacheURLRequestJobTest::OnReadComplete,
349 base::Unretained(this)));
352 // AppCacheResponseReader / Writer completion callbacks
354 void OnWriteInfoComplete(int result) {
355 EXPECT_FALSE(writer_->IsWritePending());
356 EXPECT_EQ(expected_write_result_, result);
357 ScheduleNextTask();
360 void OnWriteComplete(int result) {
361 EXPECT_FALSE(writer_->IsWritePending());
362 EXPECT_EQ(expected_write_result_, result);
363 ScheduleNextTask();
366 void OnReadInfoComplete(int result) {
367 EXPECT_FALSE(reader_->IsReadPending());
368 EXPECT_EQ(expected_read_result_, result);
369 ScheduleNextTask();
372 void OnReadComplete(int result) {
373 EXPECT_FALSE(reader_->IsReadPending());
374 EXPECT_EQ(expected_read_result_, result);
375 ScheduleNextTask();
378 // Helpers to work with HttpResponseInfo objects
380 net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
381 net::HttpResponseInfo* info = new net::HttpResponseInfo;
382 info->request_time = base::Time::Now();
383 info->response_time = base::Time::Now();
384 info->was_cached = false;
385 info->headers = new net::HttpResponseHeaders(raw_headers);
386 return info;
389 int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
390 Pickle pickle;
391 return PickleHttpResonseInfo(&pickle, info);
394 bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
395 const net::HttpResponseInfo* info2) {
396 Pickle pickle1;
397 Pickle pickle2;
398 PickleHttpResonseInfo(&pickle1, info1);
399 PickleHttpResonseInfo(&pickle2, info2);
400 return (pickle1.size() == pickle2.size()) &&
401 (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
404 int PickleHttpResonseInfo(Pickle* pickle, const net::HttpResponseInfo* info) {
405 const bool kSkipTransientHeaders = true;
406 const bool kTruncated = false;
407 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
408 return pickle->size();
411 // Helpers to fill and verify blocks of memory with a value
413 void FillData(char value, char* data, int data_len) {
414 memset(data, value, data_len);
417 bool CheckData(char value, const char* data, int data_len) {
418 for (int i = 0; i < data_len; ++i, ++data) {
419 if (*data != value)
420 return false;
422 return true;
425 // Individual Tests ---------------------------------------------------------
426 // Some of the individual tests involve multiple async steps. Each test
427 // is delineated with a section header.
429 // Basic -------------------------------------------------------------------
430 void Basic() {
431 AppCacheStorage* storage = service_->storage();
432 scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
433 GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL, NULL));
434 scoped_refptr<AppCacheURLRequestJob> job;
436 // Create an instance and see that it looks as expected.
438 job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
439 EXPECT_TRUE(job->is_waiting());
440 EXPECT_FALSE(job->is_delivering_appcache_response());
441 EXPECT_FALSE(job->is_delivering_network_response());
442 EXPECT_FALSE(job->is_delivering_error_response());
443 EXPECT_FALSE(job->has_been_started());
444 EXPECT_FALSE(job->has_been_killed());
445 EXPECT_EQ(GURL(), job->manifest_url());
446 EXPECT_EQ(kAppCacheNoCacheId, job->cache_id());
447 EXPECT_FALSE(job->entry().has_response_id());
449 TestFinished();
452 // DeliveryOrders -----------------------------------------------------
453 void DeliveryOrders() {
454 AppCacheStorage* storage = service_->storage();
455 scoped_ptr<net::URLRequest> request(empty_context_->CreateRequest(
456 GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL, NULL));
457 scoped_refptr<AppCacheURLRequestJob> job;
459 // Create an instance, give it a delivery order and see that
460 // it looks as expected.
462 job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
463 job->DeliverErrorResponse();
464 EXPECT_TRUE(job->is_delivering_error_response());
465 EXPECT_FALSE(job->has_been_started());
467 job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
468 job->DeliverNetworkResponse();
469 EXPECT_TRUE(job->is_delivering_network_response());
470 EXPECT_FALSE(job->has_been_started());
472 job = new AppCacheURLRequestJob(request.get(), NULL, storage, NULL, false);
473 const GURL kManifestUrl("http://blah/");
474 const int64 kCacheId(1);
475 const int64 kGroupId(1);
476 const AppCacheEntry kEntry(AppCacheEntry::EXPLICIT, 1);
477 job->DeliverAppCachedResponse(kManifestUrl, kCacheId, kGroupId,
478 kEntry, false);
479 EXPECT_FALSE(job->is_waiting());
480 EXPECT_TRUE(job->is_delivering_appcache_response());
481 EXPECT_FALSE(job->has_been_started());
482 EXPECT_EQ(kManifestUrl, job->manifest_url());
483 EXPECT_EQ(kCacheId, job->cache_id());
484 EXPECT_EQ(kGroupId, job->group_id());
485 EXPECT_EQ(kEntry.types(), job->entry().types());
486 EXPECT_EQ(kEntry.response_id(), job->entry().response_id());
488 TestFinished();
491 // DeliverNetworkResponse --------------------------------------------------
493 void DeliverNetworkResponse() {
494 // This test has async steps.
495 PushNextTask(
496 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse,
497 base::Unretained(this)));
499 AppCacheStorage* storage = service_->storage();
500 request_ = empty_context_->CreateRequest(GURL("http://blah/"),
501 net::DEFAULT_PRIORITY,
502 url_request_delegate_.get(),
503 NULL);
505 // Setup to create an AppCacheURLRequestJob with orders to deliver
506 // a network response.
507 AppCacheURLRequestJob* mock_job = new AppCacheURLRequestJob(
508 request_.get(), NULL, storage, NULL, false);
509 job_factory_->SetJob(mock_job);
510 mock_job->DeliverNetworkResponse();
511 EXPECT_TRUE(mock_job->is_delivering_network_response());
512 EXPECT_FALSE(mock_job->has_been_started());
514 // Start the request.
515 request_->Start();
517 // The job should have been picked up.
518 EXPECT_FALSE(job_factory_->has_job());
519 // Completion is async.
522 void VerifyDeliverNetworkResponse() {
523 EXPECT_EQ(request_->status().error(),
524 net::ERR_INTERNET_DISCONNECTED);
525 TestFinished();
528 // DeliverErrorResponse --------------------------------------------------
530 void DeliverErrorResponse() {
531 // This test has async steps.
532 PushNextTask(
533 base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse,
534 base::Unretained(this)));
536 AppCacheStorage* storage = service_->storage();
537 request_ = empty_context_->CreateRequest(GURL("http://blah/"),
538 net::DEFAULT_PRIORITY,
539 url_request_delegate_.get(),
540 NULL);
542 // Setup to create an AppCacheURLRequestJob with orders to deliver
543 // a network response.
544 AppCacheURLRequestJob* mock_job = new AppCacheURLRequestJob(
545 request_.get(), NULL, storage, NULL, false);
546 job_factory_->SetJob(mock_job);
547 mock_job->DeliverErrorResponse();
548 EXPECT_TRUE(mock_job->is_delivering_error_response());
549 EXPECT_FALSE(mock_job->has_been_started());
551 // Start the request.
552 request_->Start();
554 // The job should have been picked up.
555 EXPECT_FALSE(job_factory_->has_job());
556 // Completion is async.
559 void VerifyDeliverErrorResponse() {
560 EXPECT_EQ(request_->status().error(), net::ERR_FAILED);
561 TestFinished();
564 // DeliverSmallAppCachedResponse --------------------------------------
565 // "Small" being small enough to read completely in a single
566 // request->Read call.
568 void DeliverSmallAppCachedResponse() {
569 // This test has several async steps.
570 // 1. Write a small response to response storage.
571 // 2. Use net::URLRequest to retrieve it.
572 // 3. Verify we received what we expected to receive.
574 PushNextTask(base::Bind(
575 &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse,
576 base::Unretained(this)));
577 PushNextTask(
578 base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource,
579 base::Unretained(this), false));
581 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
582 written_response_id_ = writer_->response_id();
583 WriteBasicResponse();
584 // Continues async
587 void RequestAppCachedResource(bool start_after_delivery_orders) {
588 AppCacheStorage* storage = service_->storage();
589 request_ = empty_context_->CreateRequest(GURL("http://blah/"),
590 net::DEFAULT_PRIORITY,
591 url_request_delegate_.get(),
592 NULL);
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(),
707 NULL);
709 // Request a range, the 3 middle chars out of 'Hello'
710 net::HttpRequestHeaders extra_headers;
711 extra_headers.SetHeader("Range", "bytes= 1-3");
712 request_->SetExtraRequestHeaders(extra_headers);
714 // Create job with orders to deliver an appcached entry.
715 scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob(
716 request_.get(), NULL, storage, NULL, false));
717 job->DeliverAppCachedResponse(
718 GURL(), 0, 111,
719 AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
720 false);
721 EXPECT_TRUE(job->is_delivering_appcache_response());
723 // Start the request.
724 EXPECT_FALSE(job->has_been_started());
725 job_factory_->SetJob(job.get());
726 request_->Start();
727 EXPECT_FALSE(job_factory_->has_job());
728 EXPECT_TRUE(job->has_been_started());
729 // Completion is async.
732 void VerifyDeliverPartialResponse() {
733 EXPECT_TRUE(request_->status().is_success());
734 EXPECT_EQ(3, url_request_delegate_->amount_received_);
735 EXPECT_EQ(0, memcmp(kHttpBasicBody + 1,
736 url_request_delegate_->received_data_->data(),
737 3));
738 net::HttpResponseHeaders* headers =
739 url_request_delegate_->received_info_.headers.get();
740 EXPECT_EQ(206, headers->response_code());
741 EXPECT_EQ(3, headers->GetContentLength());
742 int64 range_start, range_end, object_size;
743 EXPECT_TRUE(
744 headers->GetContentRange(&range_start, &range_end, &object_size));
745 EXPECT_EQ(1, range_start);
746 EXPECT_EQ(3, range_end);
747 EXPECT_EQ(5, object_size);
748 TestFinished();
751 // CancelRequest --------------------------------------
753 void CancelRequest() {
754 // This test has several async steps.
755 // 1. Write a large response to response storage.
756 // 2. Use net::URLRequest to retrieve it.
757 // 3. Cancel the request after data starts coming in.
759 PushNextTask(base::Bind(
760 &AppCacheURLRequestJobTest::VerifyCancel, base::Unretained(this)));
761 PushNextTask(base::Bind(
762 &AppCacheURLRequestJobTest::RequestAppCachedResource,
763 base::Unretained(this), true));
765 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
766 written_response_id_ = writer_->response_id();
767 WriteLargeResponse();
769 url_request_delegate_->kill_after_amount_received_ = kBlockSize;
770 url_request_delegate_->kill_with_io_pending_ = false;
771 // Continues async
774 void VerifyCancel() {
775 EXPECT_EQ(net::URLRequestStatus::CANCELED,
776 request_->status().status());
777 TestFinished();
780 // CancelRequestWithIOPending --------------------------------------
782 void CancelRequestWithIOPending() {
783 // This test has several async steps.
784 // 1. Write a large response to response storage.
785 // 2. Use net::URLRequest to retrieve it.
786 // 3. Cancel the request after data starts coming in.
788 PushNextTask(base::Bind(
789 &AppCacheURLRequestJobTest::VerifyCancel, base::Unretained(this)));
790 PushNextTask(base::Bind(
791 &AppCacheURLRequestJobTest::RequestAppCachedResource,
792 base::Unretained(this), true));
794 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
795 written_response_id_ = writer_->response_id();
796 WriteLargeResponse();
798 url_request_delegate_->kill_after_amount_received_ = kBlockSize;
799 url_request_delegate_->kill_with_io_pending_ = true;
800 // Continues async
804 // Data members --------------------------------------------------------
806 scoped_ptr<base::WaitableEvent> test_finished_event_;
807 scoped_ptr<MockStorageDelegate> storage_delegate_;
808 scoped_ptr<MockAppCacheService> service_;
809 std::stack<std::pair<base::Closure, bool> > task_stack_;
811 scoped_ptr<AppCacheResponseReader> reader_;
812 scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_;
813 scoped_refptr<IOBuffer> read_buffer_;
814 int expected_read_result_;
815 int reader_deletion_count_down_;
817 int64 written_response_id_;
818 scoped_ptr<AppCacheResponseWriter> writer_;
819 scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
820 scoped_refptr<IOBuffer> write_buffer_;
821 int expected_write_result_;
822 int writer_deletion_count_down_;
824 scoped_ptr<MockURLRequestJobFactory> job_factory_;
825 scoped_ptr<net::URLRequestContext> empty_context_;
826 scoped_ptr<net::URLRequest> request_;
827 scoped_ptr<MockURLRequestDelegate> url_request_delegate_;
829 static scoped_ptr<base::Thread> io_thread_;
832 // static
833 scoped_ptr<base::Thread> AppCacheURLRequestJobTest::io_thread_;
835 TEST_F(AppCacheURLRequestJobTest, Basic) {
836 RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic);
839 TEST_F(AppCacheURLRequestJobTest, DeliveryOrders) {
840 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders);
843 TEST_F(AppCacheURLRequestJobTest, DeliverNetworkResponse) {
844 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse);
847 TEST_F(AppCacheURLRequestJobTest, DeliverErrorResponse) {
848 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse);
851 TEST_F(AppCacheURLRequestJobTest, DeliverSmallAppCachedResponse) {
852 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse);
855 TEST_F(AppCacheURLRequestJobTest, DeliverLargeAppCachedResponse) {
856 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse);
859 TEST_F(AppCacheURLRequestJobTest, DeliverPartialResponse) {
860 RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse);
863 TEST_F(AppCacheURLRequestJobTest, CancelRequest) {
864 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest);
867 TEST_F(AppCacheURLRequestJobTest, CancelRequestWithIOPending) {
868 RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending);
871 } // namespace
873 } // namespace content