Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / webkit / browser / appcache / appcache_url_request_job_unittest.cc
1 // Copyright (c) 2011 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.
4
5 #include <stack>
6 #include <utility>
7
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/pickle.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/request_priority.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/url_request/url_request.h"
20 #include "net/url_request/url_request_context.h"
21 #include "net/url_request/url_request_error_job.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "webkit/browser/appcache/appcache_response.h"
24 #include "webkit/browser/appcache/appcache_url_request_job.h"
25 #include "webkit/browser/appcache/mock_appcache_service.h"
26
27 using net::IOBuffer;
28 using net::WrappedIOBuffer;
29
30 namespace appcache {
31
32 static const char kHttpBasicHeaders[] =
33     "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
34 static const char kHttpBasicBody[] = "Hello";
35
36 static const int kNumBlocks = 4;
37 static const int kBlockSize = 1024;
38
39 class AppCacheURLRequestJobTest : public testing::Test {
40  public:
41
42   // Test Harness -------------------------------------------------------------
43   // TODO(michaeln): share this test harness with AppCacheResponseTest
44
45   class MockStorageDelegate : public AppCacheStorage::Delegate {
46    public:
47     explicit MockStorageDelegate(AppCacheURLRequestJobTest* test)
48         : loaded_info_id_(0), test_(test) {
49     }
50
51     virtual void OnResponseInfoLoaded(AppCacheResponseInfo* info,
52                                       int64 response_id) OVERRIDE {
53       loaded_info_ = info;
54       loaded_info_id_ = response_id;
55       test_->ScheduleNextTask();
56     }
57
58     scoped_refptr<AppCacheResponseInfo> loaded_info_;
59     int64 loaded_info_id_;
60     AppCacheURLRequestJobTest* test_;
61   };
62
63   class MockURLRequestDelegate : public net::URLRequest::Delegate {
64    public:
65     explicit MockURLRequestDelegate(AppCacheURLRequestJobTest* test)
66         : test_(test),
67           received_data_(new net::IOBuffer(kNumBlocks * kBlockSize)),
68           did_receive_headers_(false), amount_received_(0),
69           kill_after_amount_received_(0), kill_with_io_pending_(false) {
70     }
71
72     virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE {
73       amount_received_ = 0;
74       did_receive_headers_ = false;
75       if (request->status().is_success()) {
76         EXPECT_TRUE(request->response_headers());
77         did_receive_headers_ = true;
78         received_info_ = request->response_info();
79         ReadSome(request);
80       } else {
81         RequestComplete();
82       }
83     }
84
85     virtual void OnReadCompleted(net::URLRequest* request,
86                                  int bytes_read) OVERRIDE {
87       if (bytes_read > 0) {
88         amount_received_ += bytes_read;
89
90         if (kill_after_amount_received_ && !kill_with_io_pending_) {
91           if (amount_received_ >= kill_after_amount_received_) {
92             request->Cancel();
93             return;
94           }
95         }
96
97         ReadSome(request);
98
99         if (kill_after_amount_received_ && kill_with_io_pending_) {
100           if (amount_received_ >= kill_after_amount_received_) {
101             request->Cancel();
102             return;
103           }
104         }
105       } else {
106         RequestComplete();
107       }
108     }
109
110     void ReadSome(net::URLRequest* request) {
111       DCHECK(amount_received_ + kBlockSize <= kNumBlocks * kBlockSize);
112       scoped_refptr<IOBuffer> wrapped_buffer(
113           new net::WrappedIOBuffer(received_data_->data() + amount_received_));
114       int bytes_read = 0;
115       EXPECT_FALSE(
116           request->Read(wrapped_buffer.get(), kBlockSize, &bytes_read));
117       EXPECT_EQ(0, bytes_read);
118     }
119
120     void RequestComplete() {
121       test_->ScheduleNextTask();
122     }
123
124     AppCacheURLRequestJobTest* test_;
125     net::HttpResponseInfo received_info_;
126     scoped_refptr<net::IOBuffer> received_data_;
127     bool did_receive_headers_;
128     int amount_received_;
129     int kill_after_amount_received_;
130     bool kill_with_io_pending_;
131   };
132
133   static net::URLRequestJob* MockHttpJobFactory(
134       net::URLRequest* request,
135       net::NetworkDelegate* network_delegate,
136       const std::string& scheme) {
137     if (mock_factory_job_) {
138       net::URLRequestJob* temp = mock_factory_job_;
139       mock_factory_job_ = NULL;
140       return temp;
141     } else {
142       return new net::URLRequestErrorJob(request,
143                                          network_delegate,
144                                          net::ERR_INTERNET_DISCONNECTED);
145     }
146   }
147
148   // Helper callback to run a test on our io_thread. The io_thread is spun up
149   // once and reused for all tests.
150   template <class Method>
151   void MethodWrapper(Method method) {
152     SetUpTest();
153     (this->*method)();
154   }
155
156   static void SetUpTestCase() {
157     io_thread_.reset(new base::Thread("AppCacheURLRequestJobTest Thread"));
158     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
159     io_thread_->StartWithOptions(options);
160   }
161
162   static void TearDownTestCase() {
163     io_thread_.reset(NULL);
164   }
165
166   AppCacheURLRequestJobTest() {}
167
168   template <class Method>
169   void RunTestOnIOThread(Method method) {
170     test_finished_event_ .reset(new base::WaitableEvent(false, false));
171     io_thread_->message_loop()->PostTask(
172         FROM_HERE, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper<Method>,
173                               base::Unretained(this), method));
174     test_finished_event_->Wait();
175   }
176
177   void SetUpTest() {
178     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
179     DCHECK(task_stack_.empty());
180     orig_http_factory_ = net::URLRequest::Deprecated::RegisterProtocolFactory(
181         "http", MockHttpJobFactory);
182     url_request_delegate_.reset(new MockURLRequestDelegate(this));
183     storage_delegate_.reset(new MockStorageDelegate(this));
184     service_.reset(new MockAppCacheService());
185     expected_read_result_ = 0;
186     expected_write_result_ = 0;
187     written_response_id_ = 0;
188     reader_deletion_count_down_ = 0;
189     writer_deletion_count_down_ = 0;
190   }
191
192   void TearDownTest() {
193     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
194     net::URLRequest::Deprecated::RegisterProtocolFactory("http",
195                                                          orig_http_factory_);
196     orig_http_factory_ = NULL;
197     request_.reset();
198     url_request_delegate_.reset();
199     DCHECK(!mock_factory_job_);
200
201     while (!task_stack_.empty())
202       task_stack_.pop();
203
204     reader_.reset();
205     read_buffer_ = NULL;
206     read_info_buffer_ = NULL;
207     writer_.reset();
208     write_buffer_ = NULL;
209     write_info_buffer_ = NULL;
210     storage_delegate_.reset();
211     service_.reset();
212   }
213
214   void TestFinished() {
215     // We unwind the stack prior to finishing up to let stack
216     // based objects get deleted.
217     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
218     base::MessageLoop::current()->PostTask(
219         FROM_HERE,
220         base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound,
221                    base::Unretained(this)));
222   }
223
224   void TestFinishedUnwound() {
225     TearDownTest();
226     test_finished_event_->Signal();
227   }
228
229   void PushNextTask(const base::Closure& task) {
230     task_stack_.push(std::pair<base::Closure, bool>(task, false));
231   }
232
233   void PushNextTaskAsImmediate(const base::Closure& task) {
234     task_stack_.push(std::pair<base::Closure, bool>(task, true));
235   }
236
237   void ScheduleNextTask() {
238     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
239     if (task_stack_.empty()) {
240       TestFinished();
241       return;
242     }
243     base::Closure task =task_stack_.top().first;
244     bool immediate = task_stack_.top().second;
245     task_stack_.pop();
246     if (immediate)
247       task.Run();
248     else
249       base::MessageLoop::current()->PostTask(FROM_HERE, task);
250   }
251
252   // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
253
254   void WriteBasicResponse() {
255     scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBasicBody));
256     std::string raw_headers(kHttpBasicHeaders, arraysize(kHttpBasicHeaders));
257     WriteResponse(
258         MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBasicBody));
259   }
260
261   void WriteResponse(net::HttpResponseInfo* head,
262                      IOBuffer* body, int body_len) {
263     DCHECK(body);
264     scoped_refptr<IOBuffer> body_ref(body);
265     PushNextTask(base::Bind(&AppCacheURLRequestJobTest::WriteResponseBody,
266                             base::Unretained(this), body_ref, body_len));
267     WriteResponseHead(head);
268   }
269
270   void WriteResponseHead(net::HttpResponseInfo* head) {
271     EXPECT_FALSE(writer_->IsWritePending());
272     expected_write_result_ = GetHttpResponseInfoSize(head);
273     write_info_buffer_ = new HttpResponseInfoIOBuffer(head);
274     writer_->WriteInfo(
275         write_info_buffer_.get(),
276         base::Bind(&AppCacheURLRequestJobTest::OnWriteInfoComplete,
277                    base::Unretained(this)));
278   }
279
280   void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
281     EXPECT_FALSE(writer_->IsWritePending());
282     write_buffer_ = io_buffer;
283     expected_write_result_ = buf_len;
284     writer_->WriteData(write_buffer_.get(),
285                        buf_len,
286                        base::Bind(&AppCacheURLRequestJobTest::OnWriteComplete,
287                                   base::Unretained(this)));
288   }
289
290   void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
291     EXPECT_FALSE(reader_->IsReadPending());
292     read_buffer_ = io_buffer;
293     expected_read_result_ = buf_len;
294     reader_->ReadData(read_buffer_.get(),
295                       buf_len,
296                       base::Bind(&AppCacheURLRequestJobTest::OnReadComplete,
297                                  base::Unretained(this)));
298   }
299
300   // AppCacheResponseReader / Writer completion callbacks
301
302   void OnWriteInfoComplete(int result) {
303     EXPECT_FALSE(writer_->IsWritePending());
304     EXPECT_EQ(expected_write_result_, result);
305     ScheduleNextTask();
306   }
307
308   void OnWriteComplete(int result) {
309     EXPECT_FALSE(writer_->IsWritePending());
310     EXPECT_EQ(expected_write_result_, result);
311     ScheduleNextTask();
312   }
313
314   void OnReadInfoComplete(int result) {
315     EXPECT_FALSE(reader_->IsReadPending());
316     EXPECT_EQ(expected_read_result_, result);
317     ScheduleNextTask();
318   }
319
320   void OnReadComplete(int result) {
321     EXPECT_FALSE(reader_->IsReadPending());
322     EXPECT_EQ(expected_read_result_, result);
323     ScheduleNextTask();
324   }
325
326   // Helpers to work with HttpResponseInfo objects
327
328   net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
329     net::HttpResponseInfo* info = new net::HttpResponseInfo;
330     info->request_time = base::Time::Now();
331     info->response_time = base::Time::Now();
332     info->was_cached = false;
333     info->headers = new net::HttpResponseHeaders(raw_headers);
334     return info;
335   }
336
337   int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
338     Pickle pickle;
339     return PickleHttpResonseInfo(&pickle, info);
340   }
341
342   bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
343                                 const net::HttpResponseInfo* info2) {
344     Pickle pickle1;
345     Pickle pickle2;
346     PickleHttpResonseInfo(&pickle1, info1);
347     PickleHttpResonseInfo(&pickle2, info2);
348     return (pickle1.size() == pickle2.size()) &&
349            (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
350   }
351
352   int PickleHttpResonseInfo(Pickle* pickle, const net::HttpResponseInfo* info) {
353     const bool kSkipTransientHeaders = true;
354     const bool kTruncated = false;
355     info->Persist(pickle, kSkipTransientHeaders, kTruncated);
356     return pickle->size();
357   }
358
359   // Helpers to fill and verify blocks of memory with a value
360
361   void FillData(char value, char* data, int data_len) {
362     memset(data, value, data_len);
363   }
364
365   bool CheckData(char value, const char* data, int data_len) {
366     for (int i = 0; i < data_len; ++i, ++data) {
367       if (*data != value)
368         return false;
369     }
370     return true;
371   }
372
373   // Individual Tests ---------------------------------------------------------
374   // Some of the individual tests involve multiple async steps. Each test
375   // is delineated with a section header.
376
377   // Basic -------------------------------------------------------------------
378   void Basic() {
379     AppCacheStorage* storage = service_->storage();
380     net::URLRequest request(
381         GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL, &empty_context_);
382     scoped_refptr<AppCacheURLRequestJob> job;
383
384     // Create an instance and see that it looks as expected.
385
386     job = new AppCacheURLRequestJob(
387         &request, NULL, storage, NULL, false);
388     EXPECT_TRUE(job->is_waiting());
389     EXPECT_FALSE(job->is_delivering_appcache_response());
390     EXPECT_FALSE(job->is_delivering_network_response());
391     EXPECT_FALSE(job->is_delivering_error_response());
392     EXPECT_FALSE(job->has_been_started());
393     EXPECT_FALSE(job->has_been_killed());
394     EXPECT_EQ(GURL(), job->manifest_url());
395     EXPECT_EQ(kNoCacheId, job->cache_id());
396     EXPECT_FALSE(job->entry().has_response_id());
397
398     TestFinished();
399   }
400
401   // DeliveryOrders -----------------------------------------------------
402   void DeliveryOrders() {
403     AppCacheStorage* storage = service_->storage();
404     net::URLRequest request(
405         GURL("http://blah/"), net::DEFAULT_PRIORITY, NULL, &empty_context_);
406     scoped_refptr<AppCacheURLRequestJob> job;
407
408     // Create an instance, give it a delivery order and see that
409     // it looks as expected.
410
411     job = new AppCacheURLRequestJob(&request, NULL, storage, NULL, false);
412     job->DeliverErrorResponse();
413     EXPECT_TRUE(job->is_delivering_error_response());
414     EXPECT_FALSE(job->has_been_started());
415
416     job = new AppCacheURLRequestJob(&request, NULL, storage, NULL, false);
417     job->DeliverNetworkResponse();
418     EXPECT_TRUE(job->is_delivering_network_response());
419     EXPECT_FALSE(job->has_been_started());
420
421     job = new AppCacheURLRequestJob(&request, NULL, storage, NULL, false);
422     const GURL kManifestUrl("http://blah/");
423     const int64 kCacheId(1);
424     const int64 kGroupId(1);
425     const AppCacheEntry kEntry(AppCacheEntry::EXPLICIT, 1);
426     job->DeliverAppCachedResponse(kManifestUrl, kCacheId, kGroupId,
427                                   kEntry, false);
428     EXPECT_FALSE(job->is_waiting());
429     EXPECT_TRUE(job->is_delivering_appcache_response());
430     EXPECT_FALSE(job->has_been_started());
431     EXPECT_EQ(kManifestUrl, job->manifest_url());
432     EXPECT_EQ(kCacheId, job->cache_id());
433     EXPECT_EQ(kGroupId, job->group_id());
434     EXPECT_EQ(kEntry.types(), job->entry().types());
435     EXPECT_EQ(kEntry.response_id(), job->entry().response_id());
436
437     TestFinished();
438   }
439
440   // DeliverNetworkResponse --------------------------------------------------
441
442   void DeliverNetworkResponse() {
443     // This test has async steps.
444     PushNextTask(
445         base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverNetworkResponse,
446                    base::Unretained(this)));
447
448     AppCacheStorage* storage = service_->storage();
449     request_ = empty_context_.CreateRequest(GURL("http://blah/"),
450                                             net::DEFAULT_PRIORITY,
451                                             url_request_delegate_.get(),
452                                             NULL);
453
454     // Setup to create an AppCacheURLRequestJob with orders to deliver
455     // a network response.
456     mock_factory_job_ = new AppCacheURLRequestJob(
457         request_.get(), NULL, storage, NULL, false);
458     mock_factory_job_->DeliverNetworkResponse();
459     EXPECT_TRUE(mock_factory_job_->is_delivering_network_response());
460     EXPECT_FALSE(mock_factory_job_->has_been_started());
461
462     // Start the request.
463     request_->Start();
464
465     // The job should have been picked up.
466     EXPECT_FALSE(mock_factory_job_);
467     // Completion is async.
468   }
469
470   void VerifyDeliverNetworkResponse() {
471     EXPECT_EQ(request_->status().error(),
472               net::ERR_INTERNET_DISCONNECTED);
473     TestFinished();
474   }
475
476   // DeliverErrorResponse --------------------------------------------------
477
478   void DeliverErrorResponse() {
479     // This test has async steps.
480     PushNextTask(
481         base::Bind(&AppCacheURLRequestJobTest::VerifyDeliverErrorResponse,
482                    base::Unretained(this)));
483
484     AppCacheStorage* storage = service_->storage();
485     request_ = empty_context_.CreateRequest(GURL("http://blah/"),
486                                             net::DEFAULT_PRIORITY,
487                                             url_request_delegate_.get(),
488                                             NULL);
489
490     // Setup to create an AppCacheURLRequestJob with orders to deliver
491     // a network response.
492     mock_factory_job_ = new AppCacheURLRequestJob(
493         request_.get(), NULL, storage, NULL, false);
494     mock_factory_job_->DeliverErrorResponse();
495     EXPECT_TRUE(mock_factory_job_->is_delivering_error_response());
496     EXPECT_FALSE(mock_factory_job_->has_been_started());
497
498     // Start the request.
499     request_->Start();
500
501     // The job should have been picked up.
502     EXPECT_FALSE(mock_factory_job_);
503     // Completion is async.
504   }
505
506   void VerifyDeliverErrorResponse() {
507     EXPECT_EQ(request_->status().error(), net::ERR_FAILED);
508     TestFinished();
509   }
510
511   // DeliverSmallAppCachedResponse --------------------------------------
512   // "Small" being small enough to read completely in a single
513   // request->Read call.
514
515   void DeliverSmallAppCachedResponse() {
516     // This test has several async steps.
517     // 1. Write a small response to response storage.
518     // 2. Use net::URLRequest to retrieve it.
519     // 3. Verify we received what we expected to receive.
520
521     PushNextTask(base::Bind(
522         &AppCacheURLRequestJobTest::VerifyDeliverSmallAppCachedResponse,
523         base::Unretained(this)));
524     PushNextTask(
525         base::Bind(&AppCacheURLRequestJobTest::RequestAppCachedResource,
526                    base::Unretained(this), false));
527
528     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
529     written_response_id_ = writer_->response_id();
530     WriteBasicResponse();
531     // Continues async
532   }
533
534   void RequestAppCachedResource(bool start_after_delivery_orders) {
535     AppCacheStorage* storage = service_->storage();
536     request_ = empty_context_.CreateRequest(GURL("http://blah/"),
537                                             net::DEFAULT_PRIORITY,
538                                             url_request_delegate_.get(),
539                                             NULL);
540
541     // Setup to create an AppCacheURLRequestJob with orders to deliver
542     // a network response.
543     scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob(
544         request_.get(), NULL, storage, NULL, false));
545
546     if (start_after_delivery_orders) {
547       job->DeliverAppCachedResponse(
548           GURL(), 0, 111,
549           AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
550           false);
551       EXPECT_TRUE(job->is_delivering_appcache_response());
552     }
553
554     // Start the request.
555     EXPECT_FALSE(job->has_been_started());
556     mock_factory_job_ = job.get();
557     request_->Start();
558     EXPECT_FALSE(mock_factory_job_);
559     EXPECT_TRUE(job->has_been_started());
560
561     if (!start_after_delivery_orders) {
562       job->DeliverAppCachedResponse(
563           GURL(), 0, 111,
564           AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
565           false);
566       EXPECT_TRUE(job->is_delivering_appcache_response());
567     }
568
569     // Completion is async.
570   }
571
572   void VerifyDeliverSmallAppCachedResponse() {
573     EXPECT_TRUE(request_->status().is_success());
574     EXPECT_TRUE(CompareHttpResponseInfos(
575         write_info_buffer_->http_info.get(),
576         &url_request_delegate_->received_info_));
577     EXPECT_EQ(5, url_request_delegate_->amount_received_);
578     EXPECT_EQ(0, memcmp(kHttpBasicBody,
579                         url_request_delegate_->received_data_->data(),
580                         strlen(kHttpBasicBody)));
581     TestFinished();
582   }
583
584   // DeliverLargeAppCachedResponse --------------------------------------
585   // "Large" enough to require multiple calls to request->Read to complete.
586
587   void DeliverLargeAppCachedResponse() {
588     // This test has several async steps.
589     // 1. Write a large response to response storage.
590     // 2. Use net::URLRequest to retrieve it.
591     // 3. Verify we received what we expected to receive.
592
593     PushNextTask(base::Bind(
594        &AppCacheURLRequestJobTest::VerifyDeliverLargeAppCachedResponse,
595        base::Unretained(this)));
596     PushNextTask(base::Bind(
597        &AppCacheURLRequestJobTest::RequestAppCachedResource,
598        base::Unretained(this), true));
599
600     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
601     written_response_id_ = writer_->response_id();
602     WriteLargeResponse();
603     // Continues async
604   }
605
606   void WriteLargeResponse() {
607     // 3, 1k blocks
608     static const char kHttpHeaders[] =
609         "HTTP/1.0 200 OK\0Content-Length: 3072\0\0";
610     scoped_refptr<IOBuffer> body(new IOBuffer(kBlockSize * 3));
611     char* p = body->data();
612     for (int i = 0; i < 3; ++i, p += kBlockSize)
613       FillData(i + 1, p, kBlockSize);
614     std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
615     WriteResponse(
616         MakeHttpResponseInfo(raw_headers), body.get(), kBlockSize * 3);
617   }
618
619   void VerifyDeliverLargeAppCachedResponse() {
620     EXPECT_TRUE(request_->status().is_success());
621     EXPECT_TRUE(CompareHttpResponseInfos(
622         write_info_buffer_->http_info.get(),
623         &url_request_delegate_->received_info_));
624     EXPECT_EQ(3072, url_request_delegate_->amount_received_);
625     char* p = url_request_delegate_->received_data_->data();
626     for (int i = 0; i < 3; ++i, p += kBlockSize)
627       EXPECT_TRUE(CheckData(i + 1, p, kBlockSize));
628     TestFinished();
629   }
630
631   // DeliverPartialResponse --------------------------------------
632
633   void DeliverPartialResponse() {
634     // This test has several async steps.
635     // 1. Write a small response to response storage.
636     // 2. Use net::URLRequest to retrieve it a subset using a range request
637     // 3. Verify we received what we expected to receive.
638     PushNextTask(base::Bind(
639        &AppCacheURLRequestJobTest::VerifyDeliverPartialResponse,
640        base::Unretained(this)));
641     PushNextTask(base::Bind(
642        &AppCacheURLRequestJobTest::MakeRangeRequest, base::Unretained(this)));
643     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
644     written_response_id_ = writer_->response_id();
645     WriteBasicResponse();
646     // Continues async
647   }
648
649   void MakeRangeRequest() {
650     AppCacheStorage* storage = service_->storage();
651     request_ = empty_context_.CreateRequest(GURL("http://blah/"),
652                                             net::DEFAULT_PRIORITY,
653                                             url_request_delegate_.get(),
654                                             NULL);
655
656     // Request a range, the 3 middle chars out of 'Hello'
657     net::HttpRequestHeaders extra_headers;
658     extra_headers.SetHeader("Range", "bytes= 1-3");
659     request_->SetExtraRequestHeaders(extra_headers);
660
661     // Create job with orders to deliver an appcached entry.
662     scoped_refptr<AppCacheURLRequestJob> job(new AppCacheURLRequestJob(
663         request_.get(), NULL, storage, NULL, false));
664     job->DeliverAppCachedResponse(
665         GURL(), 0, 111,
666         AppCacheEntry(AppCacheEntry::EXPLICIT, written_response_id_),
667         false);
668     EXPECT_TRUE(job->is_delivering_appcache_response());
669
670     // Start the request.
671     EXPECT_FALSE(job->has_been_started());
672     mock_factory_job_ = job.get();
673     request_->Start();
674     EXPECT_FALSE(mock_factory_job_);
675     EXPECT_TRUE(job->has_been_started());
676     // Completion is async.
677   }
678
679   void VerifyDeliverPartialResponse() {
680     EXPECT_TRUE(request_->status().is_success());
681     EXPECT_EQ(3, url_request_delegate_->amount_received_);
682     EXPECT_EQ(0, memcmp(kHttpBasicBody + 1,
683                         url_request_delegate_->received_data_->data(),
684                         3));
685     net::HttpResponseHeaders* headers =
686         url_request_delegate_->received_info_.headers.get();
687     EXPECT_EQ(206, headers->response_code());
688     EXPECT_EQ(3, headers->GetContentLength());
689     int64 range_start, range_end, object_size;
690     EXPECT_TRUE(
691         headers->GetContentRange(&range_start, &range_end, &object_size));
692     EXPECT_EQ(1, range_start);
693     EXPECT_EQ(3, range_end);
694     EXPECT_EQ(5, object_size);
695     TestFinished();
696   }
697
698   // CancelRequest --------------------------------------
699
700   void CancelRequest() {
701     // This test has several async steps.
702     // 1. Write a large response to response storage.
703     // 2. Use net::URLRequest to retrieve it.
704     // 3. Cancel the request after data starts coming in.
705
706     PushNextTask(base::Bind(
707        &AppCacheURLRequestJobTest::VerifyCancel, base::Unretained(this)));
708     PushNextTask(base::Bind(
709        &AppCacheURLRequestJobTest::RequestAppCachedResource,
710        base::Unretained(this), true));
711
712     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
713     written_response_id_ = writer_->response_id();
714     WriteLargeResponse();
715
716     url_request_delegate_->kill_after_amount_received_ = kBlockSize;
717     url_request_delegate_->kill_with_io_pending_ = false;
718     // Continues async
719   }
720
721   void VerifyCancel() {
722     EXPECT_EQ(net::URLRequestStatus::CANCELED,
723               request_->status().status());
724     TestFinished();
725   }
726
727   // CancelRequestWithIOPending --------------------------------------
728
729   void CancelRequestWithIOPending() {
730     // This test has several async steps.
731     // 1. Write a large response to response storage.
732     // 2. Use net::URLRequest to retrieve it.
733     // 3. Cancel the request after data starts coming in.
734
735     PushNextTask(base::Bind(
736        &AppCacheURLRequestJobTest::VerifyCancel, base::Unretained(this)));
737     PushNextTask(base::Bind(
738        &AppCacheURLRequestJobTest::RequestAppCachedResource,
739        base::Unretained(this), true));
740
741     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
742     written_response_id_ = writer_->response_id();
743     WriteLargeResponse();
744
745     url_request_delegate_->kill_after_amount_received_ = kBlockSize;
746     url_request_delegate_->kill_with_io_pending_ = true;
747     // Continues async
748   }
749
750
751   // Data members --------------------------------------------------------
752
753   scoped_ptr<base::WaitableEvent> test_finished_event_;
754   scoped_ptr<MockStorageDelegate> storage_delegate_;
755   scoped_ptr<MockAppCacheService> service_;
756   std::stack<std::pair<base::Closure, bool> > task_stack_;
757
758   scoped_ptr<AppCacheResponseReader> reader_;
759   scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_;
760   scoped_refptr<IOBuffer> read_buffer_;
761   int expected_read_result_;
762   int reader_deletion_count_down_;
763
764   int64 written_response_id_;
765   scoped_ptr<AppCacheResponseWriter> writer_;
766   scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
767   scoped_refptr<IOBuffer> write_buffer_;
768   int expected_write_result_;
769   int writer_deletion_count_down_;
770
771   net::URLRequest::ProtocolFactory* orig_http_factory_;
772   net::URLRequestContext empty_context_;
773   scoped_ptr<net::URLRequest> request_;
774   scoped_ptr<MockURLRequestDelegate> url_request_delegate_;
775
776   static scoped_ptr<base::Thread> io_thread_;
777   static AppCacheURLRequestJob* mock_factory_job_;
778 };
779
780 // static
781 scoped_ptr<base::Thread> AppCacheURLRequestJobTest::io_thread_;
782 AppCacheURLRequestJob* AppCacheURLRequestJobTest::mock_factory_job_ = NULL;
783
784 TEST_F(AppCacheURLRequestJobTest, Basic) {
785   RunTestOnIOThread(&AppCacheURLRequestJobTest::Basic);
786 }
787
788 TEST_F(AppCacheURLRequestJobTest, DeliveryOrders) {
789   RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliveryOrders);
790 }
791
792 TEST_F(AppCacheURLRequestJobTest, DeliverNetworkResponse) {
793   RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverNetworkResponse);
794 }
795
796 TEST_F(AppCacheURLRequestJobTest, DeliverErrorResponse) {
797   RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverErrorResponse);
798 }
799
800 TEST_F(AppCacheURLRequestJobTest, DeliverSmallAppCachedResponse) {
801   RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverSmallAppCachedResponse);
802 }
803
804 TEST_F(AppCacheURLRequestJobTest, DeliverLargeAppCachedResponse) {
805   RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverLargeAppCachedResponse);
806 }
807
808 TEST_F(AppCacheURLRequestJobTest, DeliverPartialResponse) {
809   RunTestOnIOThread(&AppCacheURLRequestJobTest::DeliverPartialResponse);
810 }
811
812 TEST_F(AppCacheURLRequestJobTest, CancelRequest) {
813   RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequest);
814 }
815
816 TEST_F(AppCacheURLRequestJobTest, CancelRequestWithIOPending) {
817   RunTestOnIOThread(&AppCacheURLRequestJobTest::CancelRequestWithIOPending);
818 }
819
820 }  // namespace appcache