Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / appcache / appcache_response_unittest.cc
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.
4
5 #include <stack>
6 #include <string>
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/pickle.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/thread.h"
16 #include "content/browser/appcache/appcache_response.h"
17 #include "content/browser/appcache/mock_appcache_service.h"
18 #include "net/base/io_buffer.h"
19 #include "net/base/net_errors.h"
20 #include "net/http/http_response_headers.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 using net::IOBuffer;
24 using net::WrappedIOBuffer;
25
26 namespace content {
27
28 static const int kNumBlocks = 4;
29 static const int kBlockSize = 1024;
30 static const int kNoSuchResponseId = 123;
31
32 class AppCacheResponseTest : public testing::Test {
33  public:
34   // Test Harness -------------------------------------------------------------
35
36   // Helper class used to verify test results
37   class MockStorageDelegate : public AppCacheStorage::Delegate {
38    public:
39     explicit MockStorageDelegate(AppCacheResponseTest* test)
40         : loaded_info_id_(0), test_(test) {
41     }
42
43     virtual void OnResponseInfoLoaded(AppCacheResponseInfo* info,
44                                       int64 response_id) OVERRIDE {
45       loaded_info_ = info;
46       loaded_info_id_ = response_id;
47       test_->ScheduleNextTask();
48     }
49
50     scoped_refptr<AppCacheResponseInfo> loaded_info_;
51     int64 loaded_info_id_;
52     AppCacheResponseTest* test_;
53   };
54
55   // Helper callback to run a test on our io_thread. The io_thread is spun up
56   // once and reused for all tests.
57   template <class Method>
58   void MethodWrapper(Method method) {
59     SetUpTest();
60     (this->*method)();
61   }
62
63   static void SetUpTestCase() {
64     io_thread_.reset(new base::Thread("AppCacheResponseTest Thread"));
65     base::Thread::Options options(base::MessageLoop::TYPE_IO, 0);
66     io_thread_->StartWithOptions(options);
67   }
68
69   static void TearDownTestCase() {
70     io_thread_.reset(NULL);
71   }
72
73   AppCacheResponseTest() {}
74
75   template <class Method>
76   void RunTestOnIOThread(Method method) {
77     test_finished_event_ .reset(new base::WaitableEvent(false, false));
78     io_thread_->message_loop()->PostTask(
79         FROM_HERE, base::Bind(&AppCacheResponseTest::MethodWrapper<Method>,
80                               base::Unretained(this), method));
81     test_finished_event_->Wait();
82   }
83
84   void SetUpTest() {
85     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
86     DCHECK(task_stack_.empty());
87     storage_delegate_.reset(new MockStorageDelegate(this));
88     service_.reset(new MockAppCacheService());
89     expected_read_result_ = 0;
90     expected_write_result_ = 0;
91     written_response_id_ = 0;
92     should_delete_reader_in_completion_callback_ = false;
93     should_delete_writer_in_completion_callback_ = false;
94     reader_deletion_count_down_ = 0;
95     writer_deletion_count_down_ = 0;
96     read_callback_was_called_ = false;
97     write_callback_was_called_ = false;
98   }
99
100   void TearDownTest() {
101     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
102     while (!task_stack_.empty())
103       task_stack_.pop();
104
105     reader_.reset();
106     read_buffer_ = NULL;
107     read_info_buffer_ = NULL;
108     writer_.reset();
109     write_buffer_ = NULL;
110     write_info_buffer_ = NULL;
111     storage_delegate_.reset();
112     service_.reset();
113   }
114
115   void TestFinished() {
116     // We unwind the stack prior to finishing up to let stack
117     // based objects get deleted.
118     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
119     base::MessageLoop::current()->PostTask(
120         FROM_HERE, base::Bind(&AppCacheResponseTest::TestFinishedUnwound,
121                               base::Unretained(this)));
122   }
123
124   void TestFinishedUnwound() {
125     TearDownTest();
126     test_finished_event_->Signal();
127   }
128
129   void PushNextTask(const base::Closure& task) {
130     task_stack_.push(std::pair<base::Closure, bool>(task, false));
131   }
132
133   void PushNextTaskAsImmediate(const base::Closure& task) {
134     task_stack_.push(std::pair<base::Closure, bool>(task, true));
135   }
136
137   void ScheduleNextTask() {
138     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
139     if (task_stack_.empty()) {
140       TestFinished();
141       return;
142     }
143     base::Closure task = task_stack_.top().first;
144     bool immediate = task_stack_.top().second;
145     task_stack_.pop();
146     if (immediate)
147       task.Run();
148     else
149       base::MessageLoop::current()->PostTask(FROM_HERE, task);
150   }
151
152   // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
153
154   void WriteBasicResponse() {
155     static const char kHttpHeaders[] =
156         "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
157     static const char kHttpBody[] = "Hello";
158     scoped_refptr<IOBuffer> body(new WrappedIOBuffer(kHttpBody));
159     std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
160     WriteResponse(
161         MakeHttpResponseInfo(raw_headers), body.get(), strlen(kHttpBody));
162   }
163
164   int basic_response_size() { return 5; }  // should match kHttpBody above
165
166   void WriteResponse(net::HttpResponseInfo* head,
167                      IOBuffer* body, int body_len) {
168     DCHECK(body);
169     scoped_refptr<IOBuffer> body_ref(body);
170     PushNextTask(base::Bind(&AppCacheResponseTest::WriteResponseBody,
171                             base::Unretained(this), body_ref, body_len));
172     WriteResponseHead(head);
173   }
174
175   void WriteResponseHead(net::HttpResponseInfo* head) {
176     EXPECT_FALSE(writer_->IsWritePending());
177     expected_write_result_ = GetHttpResponseInfoSize(head);
178     write_info_buffer_ = new HttpResponseInfoIOBuffer(head);
179     writer_->WriteInfo(write_info_buffer_.get(),
180                        base::Bind(&AppCacheResponseTest::OnWriteInfoComplete,
181                                   base::Unretained(this)));
182   }
183
184   void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
185     EXPECT_FALSE(writer_->IsWritePending());
186     write_buffer_ = io_buffer;
187     expected_write_result_ = buf_len;
188     writer_->WriteData(write_buffer_.get(),
189                        buf_len,
190                        base::Bind(&AppCacheResponseTest::OnWriteComplete,
191                                   base::Unretained(this)));
192   }
193
194   void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
195     EXPECT_FALSE(reader_->IsReadPending());
196     read_buffer_ = io_buffer;
197     expected_read_result_ = buf_len;
198     reader_->ReadData(read_buffer_.get(),
199                       buf_len,
200                       base::Bind(&AppCacheResponseTest::OnReadComplete,
201                                  base::Unretained(this)));
202   }
203
204   // AppCacheResponseReader / Writer completion callbacks
205
206   void OnWriteInfoComplete(int result) {
207     EXPECT_FALSE(writer_->IsWritePending());
208     EXPECT_EQ(expected_write_result_, result);
209     ScheduleNextTask();
210   }
211
212   void OnWriteComplete(int result) {
213     EXPECT_FALSE(writer_->IsWritePending());
214     write_callback_was_called_ = true;
215     EXPECT_EQ(expected_write_result_, result);
216     if (should_delete_writer_in_completion_callback_ &&
217         --writer_deletion_count_down_ == 0) {
218       writer_.reset();
219     }
220     ScheduleNextTask();
221   }
222
223   void OnReadInfoComplete(int result) {
224     EXPECT_FALSE(reader_->IsReadPending());
225     EXPECT_EQ(expected_read_result_, result);
226     ScheduleNextTask();
227   }
228
229   void OnReadComplete(int result) {
230     EXPECT_FALSE(reader_->IsReadPending());
231     read_callback_was_called_ = true;
232     EXPECT_EQ(expected_read_result_, result);
233     if (should_delete_reader_in_completion_callback_ &&
234         --reader_deletion_count_down_ == 0) {
235       reader_.reset();
236     }
237     ScheduleNextTask();
238   }
239
240   // Helpers to work with HttpResponseInfo objects
241
242   net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
243     net::HttpResponseInfo* info = new net::HttpResponseInfo;
244     info->request_time = base::Time::Now();
245     info->response_time = base::Time::Now();
246     info->was_cached = false;
247     info->headers = new net::HttpResponseHeaders(raw_headers);
248     return info;
249   }
250
251   int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
252     Pickle pickle;
253     return PickleHttpResonseInfo(&pickle, info);
254   }
255
256   bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
257                                 const net::HttpResponseInfo* info2) {
258     Pickle pickle1;
259     Pickle pickle2;
260     PickleHttpResonseInfo(&pickle1, info1);
261     PickleHttpResonseInfo(&pickle2, info2);
262     return (pickle1.size() == pickle2.size()) &&
263            (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
264   }
265
266   int PickleHttpResonseInfo(Pickle* pickle, const net::HttpResponseInfo* info) {
267     const bool kSkipTransientHeaders = true;
268     const bool kTruncated = false;
269     info->Persist(pickle, kSkipTransientHeaders, kTruncated);
270     return pickle->size();
271   }
272
273   // Helpers to fill and verify blocks of memory with a value
274
275   void FillData(char value, char* data, int data_len) {
276     memset(data, value, data_len);
277   }
278
279   bool CheckData(char value, const char* data, int data_len) {
280     for (int i = 0; i < data_len; ++i, ++data) {
281       if (*data != value)
282         return false;
283     }
284     return true;
285   }
286
287   // Individual Tests ---------------------------------------------------------
288   // Most of the individual tests involve multiple async steps. Each test
289   // is delineated with a section header.
290
291
292   // ReadNonExistentResponse -------------------------------------------
293   void ReadNonExistentResponse() {
294     // 1. Attempt to ReadInfo
295     // 2. Attempt to ReadData
296
297     reader_.reset(service_->storage()->CreateResponseReader(
298         GURL(), 0, kNoSuchResponseId));
299
300     // Push tasks in reverse order
301     PushNextTask(base::Bind(&AppCacheResponseTest::ReadNonExistentData,
302                             base::Unretained(this)));
303     PushNextTask(base::Bind(&AppCacheResponseTest::ReadNonExistentInfo,
304                             base::Unretained(this)));
305     ScheduleNextTask();
306   }
307
308   void ReadNonExistentInfo() {
309     EXPECT_FALSE(reader_->IsReadPending());
310     read_info_buffer_ = new HttpResponseInfoIOBuffer();
311     reader_->ReadInfo(read_info_buffer_.get(),
312                       base::Bind(&AppCacheResponseTest::OnReadInfoComplete,
313                                  base::Unretained(this)));
314     EXPECT_TRUE(reader_->IsReadPending());
315     expected_read_result_ = net::ERR_CACHE_MISS;
316   }
317
318   void ReadNonExistentData() {
319     EXPECT_FALSE(reader_->IsReadPending());
320     read_buffer_ = new IOBuffer(kBlockSize);
321     reader_->ReadData(read_buffer_.get(),
322                       kBlockSize,
323                       base::Bind(&AppCacheResponseTest::OnReadComplete,
324                                  base::Unretained(this)));
325     EXPECT_TRUE(reader_->IsReadPending());
326     expected_read_result_ = net::ERR_CACHE_MISS;
327   }
328
329   // LoadResponseInfo_Miss ----------------------------------------------------
330   void LoadResponseInfo_Miss() {
331     PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Miss_Verify,
332                             base::Unretained(this)));
333     service_->storage()->LoadResponseInfo(GURL(), 0, kNoSuchResponseId,
334                                           storage_delegate_.get());
335   }
336
337   void LoadResponseInfo_Miss_Verify() {
338     EXPECT_EQ(kNoSuchResponseId, storage_delegate_->loaded_info_id_);
339     EXPECT_TRUE(!storage_delegate_->loaded_info_.get());
340     TestFinished();
341   }
342
343   // LoadResponseInfo_Hit ----------------------------------------------------
344   void LoadResponseInfo_Hit() {
345     // This tests involves multiple async steps.
346     // 1. Write a response headers and body to storage
347     //   a. headers
348     //   b. body
349     // 2. Use LoadResponseInfo to read the response headers back out
350     PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Hit_Step2,
351                             base::Unretained(this)));
352     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
353     written_response_id_ = writer_->response_id();
354     WriteBasicResponse();
355   }
356
357   void LoadResponseInfo_Hit_Step2() {
358     writer_.reset();
359     PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Hit_Verify,
360                             base::Unretained(this)));
361     service_->storage()->LoadResponseInfo(GURL(), 0, written_response_id_,
362                                           storage_delegate_.get());
363   }
364
365   void LoadResponseInfo_Hit_Verify() {
366     EXPECT_EQ(written_response_id_, storage_delegate_->loaded_info_id_);
367     EXPECT_TRUE(storage_delegate_->loaded_info_.get());
368     EXPECT_TRUE(CompareHttpResponseInfos(
369         write_info_buffer_->http_info.get(),
370         storage_delegate_->loaded_info_->http_response_info()));
371     EXPECT_EQ(basic_response_size(),
372               storage_delegate_->loaded_info_->response_data_size());
373     TestFinished();
374   }
375
376   // AmountWritten ----------------------------------------------------
377
378   void AmountWritten() {
379     static const char kHttpHeaders[] = "HTTP/1.0 200 OK\0\0";
380     std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
381     net::HttpResponseInfo* head = MakeHttpResponseInfo(raw_headers);
382     int expected_amount_written =
383         GetHttpResponseInfoSize(head) + kNumBlocks * kBlockSize;
384
385     // Push tasks in reverse order.
386     PushNextTask(base::Bind(&AppCacheResponseTest::Verify_AmountWritten,
387                             base::Unretained(this), expected_amount_written));
388     for (int i = 0; i < kNumBlocks; ++i) {
389       PushNextTask(base::Bind(&AppCacheResponseTest::WriteOneBlock,
390                               base::Unretained(this), kNumBlocks - i));
391     }
392     PushNextTask(base::Bind(&AppCacheResponseTest::WriteResponseHead,
393                             base::Unretained(this), head));
394
395     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
396     written_response_id_ = writer_->response_id();
397     ScheduleNextTask();
398   }
399
400   void Verify_AmountWritten(int expected_amount_written) {
401     EXPECT_EQ(expected_amount_written, writer_->amount_written());
402     TestFinished();
403   }
404
405
406   // WriteThenVariouslyReadResponse -------------------------------------------
407
408   void WriteThenVariouslyReadResponse() {
409     // This tests involves multiple async steps.
410     // 1. First, write a large body using multiple writes, we don't bother
411     //    with a response head for this test.
412     // 2. Read the entire body, using multiple reads
413     // 3. Read the entire body, using one read.
414     // 4. Attempt to read beyond the EOF.
415     // 5. Read just a range.
416     // 6. Attempt to read beyond EOF of a range.
417
418     // Push tasks in reverse order
419     PushNextTask(base::Bind(&AppCacheResponseTest::ReadRangeFullyBeyondEOF,
420                             base::Unretained(this)));
421     PushNextTask(base::Bind(&AppCacheResponseTest::ReadRangePartiallyBeyondEOF,
422                             base::Unretained(this)));
423     PushNextTask(base::Bind(&AppCacheResponseTest::ReadPastEOF,
424                             base::Unretained(this)));
425     PushNextTask(base::Bind(&AppCacheResponseTest::ReadRange,
426                             base::Unretained(this)));
427     PushNextTask(base::Bind(&AppCacheResponseTest::ReadPastEOF,
428                             base::Unretained(this)));
429     PushNextTask(base::Bind(&AppCacheResponseTest::ReadAllAtOnce,
430                             base::Unretained(this)));
431     PushNextTask(base::Bind(&AppCacheResponseTest::ReadInBlocks,
432                             base::Unretained(this)));
433     PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks,
434                             base::Unretained(this)));
435
436     // Get them going.
437     ScheduleNextTask();
438   }
439
440   void WriteOutBlocks() {
441     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
442     written_response_id_ = writer_->response_id();
443     for (int i = 0; i < kNumBlocks; ++i) {
444       PushNextTask(base::Bind(&AppCacheResponseTest::WriteOneBlock,
445                               base::Unretained(this), kNumBlocks - i));
446     }
447     ScheduleNextTask();
448   }
449
450   void WriteOneBlock(int block_number) {
451     scoped_refptr<IOBuffer> io_buffer(
452         new IOBuffer(kBlockSize));
453     FillData(block_number, io_buffer->data(), kBlockSize);
454     WriteResponseBody(io_buffer, kBlockSize);
455   }
456
457   void ReadInBlocks() {
458     writer_.reset();
459     reader_.reset(service_->storage()->CreateResponseReader(
460         GURL(), 0, written_response_id_));
461     for (int i = 0; i < kNumBlocks; ++i) {
462       PushNextTask(base::Bind(&AppCacheResponseTest::ReadOneBlock,
463                               base::Unretained(this), kNumBlocks - i));
464     }
465     ScheduleNextTask();
466   }
467
468   void ReadOneBlock(int block_number) {
469     PushNextTask(base::Bind(&AppCacheResponseTest::VerifyOneBlock,
470                             base::Unretained(this), block_number));
471     ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
472   }
473
474   void VerifyOneBlock(int block_number) {
475     EXPECT_TRUE(CheckData(block_number, read_buffer_->data(), kBlockSize));
476     ScheduleNextTask();
477   }
478
479   void ReadAllAtOnce() {
480     PushNextTask(base::Bind(&AppCacheResponseTest::VerifyAllAtOnce,
481                             base::Unretained(this)));
482     reader_.reset(service_->storage()->CreateResponseReader(
483         GURL(), 0, written_response_id_));
484     int big_size = kNumBlocks * kBlockSize;
485     ReadResponseBody(new IOBuffer(big_size), big_size);
486   }
487
488   void VerifyAllAtOnce() {
489     char* p = read_buffer_->data();
490     for (int i = 0; i < kNumBlocks; ++i, p += kBlockSize)
491       EXPECT_TRUE(CheckData(i + 1, p, kBlockSize));
492     ScheduleNextTask();
493   }
494
495   void ReadPastEOF() {
496     EXPECT_FALSE(reader_->IsReadPending());
497     read_buffer_ = new IOBuffer(kBlockSize);
498     expected_read_result_ = 0;
499     reader_->ReadData(read_buffer_.get(),
500                       kBlockSize,
501                       base::Bind(&AppCacheResponseTest::OnReadComplete,
502                                  base::Unretained(this)));
503   }
504
505   void ReadRange() {
506     PushNextTask(base::Bind(&AppCacheResponseTest::VerifyRange,
507                             base::Unretained(this)));
508     reader_.reset(service_->storage()->CreateResponseReader(
509         GURL(), 0, written_response_id_));
510     reader_->SetReadRange(kBlockSize, kBlockSize);
511     ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
512   }
513
514   void VerifyRange() {
515     EXPECT_TRUE(CheckData(2, read_buffer_->data(), kBlockSize));
516     ScheduleNextTask();  // ReadPastEOF is scheduled next
517   }
518
519   void ReadRangePartiallyBeyondEOF() {
520     PushNextTask(base::Bind(&AppCacheResponseTest::VerifyRangeBeyondEOF,
521                             base::Unretained(this)));
522     reader_.reset(service_->storage()->CreateResponseReader(
523         GURL(), 0, written_response_id_));
524     reader_->SetReadRange(kBlockSize, kNumBlocks * kBlockSize);
525     ReadResponseBody(new IOBuffer(kNumBlocks * kBlockSize),
526                      kNumBlocks * kBlockSize);
527     expected_read_result_ = (kNumBlocks - 1) * kBlockSize;
528   }
529
530   void VerifyRangeBeyondEOF() {
531     // Just verify the first 1k
532     VerifyRange();
533   }
534
535   void ReadRangeFullyBeyondEOF() {
536     reader_.reset(service_->storage()->CreateResponseReader(
537         GURL(), 0, written_response_id_));
538     reader_->SetReadRange((kNumBlocks * kBlockSize) + 1, kBlockSize);
539     ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
540     expected_read_result_ = 0;
541   }
542
543   // IOChaining -------------------------------------------
544   void IOChaining() {
545     // 1. Write several blocks out initiating the subsequent write
546     //    from within the completion callback of the previous write.
547     // 2. Read and verify several blocks in similarly chaining reads.
548
549     // Push tasks in reverse order
550     PushNextTaskAsImmediate(
551         base::Bind(&AppCacheResponseTest::ReadInBlocksImmediately,
552                    base::Unretained(this)));
553     PushNextTaskAsImmediate(
554         base::Bind(&AppCacheResponseTest::WriteOutBlocksImmediately,
555                    base::Unretained(this)));
556
557     // Get them going.
558     ScheduleNextTask();
559   }
560
561   void WriteOutBlocksImmediately() {
562     writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
563     written_response_id_ = writer_->response_id();
564     for (int i = 0; i < kNumBlocks; ++i) {
565       PushNextTaskAsImmediate(
566           base::Bind(&AppCacheResponseTest::WriteOneBlock,
567                      base::Unretained(this), kNumBlocks - i));
568     }
569     ScheduleNextTask();
570   }
571
572   void ReadInBlocksImmediately() {
573     writer_.reset();
574     reader_.reset(service_->storage()->CreateResponseReader(
575         GURL(), 0, written_response_id_));
576     for (int i = 0; i < kNumBlocks; ++i) {
577       PushNextTaskAsImmediate(
578           base::Bind(&AppCacheResponseTest::ReadOneBlockImmediately,
579                      base::Unretained(this),
580           kNumBlocks - i));
581     }
582     ScheduleNextTask();
583   }
584
585   void ReadOneBlockImmediately(int block_number) {
586     PushNextTaskAsImmediate(base::Bind(&AppCacheResponseTest::VerifyOneBlock,
587                                        base::Unretained(this), block_number));
588     ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
589   }
590
591   // DeleteWithinCallbacks -------------------------------------------
592   void DeleteWithinCallbacks() {
593     // 1. Write out a few blocks normally, and upon
594     //    completion of the last write, delete the writer.
595     // 2. Read in a few blocks normally, and upon completion
596     //    of the last read, delete the reader.
597
598     should_delete_reader_in_completion_callback_ = true;
599     reader_deletion_count_down_ = kNumBlocks;
600     should_delete_writer_in_completion_callback_ = true;
601     writer_deletion_count_down_ = kNumBlocks;
602
603     PushNextTask(base::Bind(&AppCacheResponseTest::ReadInBlocks,
604                             base::Unretained(this)));
605     PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks,
606                             base::Unretained(this)));
607     ScheduleNextTask();
608   }
609
610   // DeleteWithIOPending -------------------------------------------
611   void DeleteWithIOPending() {
612     // 1. Write a few blocks normally.
613     // 2. Start a write, delete with it pending.
614     // 3. Start a read, delete with it pending.
615     PushNextTask(base::Bind(&AppCacheResponseTest::ReadThenDelete,
616                             base::Unretained(this)));
617     PushNextTask(base::Bind(&AppCacheResponseTest::WriteThenDelete,
618                             base::Unretained(this)));
619     PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks,
620                             base::Unretained(this)));
621     ScheduleNextTask();
622   }
623
624   void WriteThenDelete() {
625     write_callback_was_called_ = false;
626     WriteOneBlock(5);
627     EXPECT_TRUE(writer_->IsWritePending());
628     writer_.reset();
629     ScheduleNextTask();
630   }
631
632   void ReadThenDelete() {
633     read_callback_was_called_ = false;
634     reader_.reset(service_->storage()->CreateResponseReader(
635         GURL(), 0, written_response_id_));
636     ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
637     EXPECT_TRUE(reader_->IsReadPending());
638     reader_.reset();
639
640     // Wait a moment to verify no callbacks.
641     base::MessageLoop::current()->PostDelayedTask(
642         FROM_HERE, base::Bind(&AppCacheResponseTest::VerifyNoCallbacks,
643                               base::Unretained(this)),
644         base::TimeDelta::FromMilliseconds(10));
645   }
646
647   void VerifyNoCallbacks() {
648     EXPECT_TRUE(!write_callback_was_called_);
649     EXPECT_TRUE(!read_callback_was_called_);
650     TestFinished();
651   }
652
653   // Data members
654
655   scoped_ptr<base::WaitableEvent> test_finished_event_;
656   scoped_ptr<MockStorageDelegate> storage_delegate_;
657   scoped_ptr<MockAppCacheService> service_;
658   std::stack<std::pair<base::Closure, bool> > task_stack_;
659
660   scoped_ptr<AppCacheResponseReader> reader_;
661   scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_;
662   scoped_refptr<IOBuffer> read_buffer_;
663   int expected_read_result_;
664   bool should_delete_reader_in_completion_callback_;
665   int reader_deletion_count_down_;
666   bool read_callback_was_called_;
667
668   int64 written_response_id_;
669   scoped_ptr<AppCacheResponseWriter> writer_;
670   scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
671   scoped_refptr<IOBuffer> write_buffer_;
672   int expected_write_result_;
673   bool should_delete_writer_in_completion_callback_;
674   int writer_deletion_count_down_;
675   bool write_callback_was_called_;
676
677   static scoped_ptr<base::Thread> io_thread_;
678 };
679
680 // static
681 scoped_ptr<base::Thread> AppCacheResponseTest::io_thread_;
682
683 TEST_F(AppCacheResponseTest, ReadNonExistentResponse) {
684   RunTestOnIOThread(&AppCacheResponseTest::ReadNonExistentResponse);
685 }
686
687 TEST_F(AppCacheResponseTest, LoadResponseInfo_Miss) {
688   RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Miss);
689 }
690
691 TEST_F(AppCacheResponseTest, LoadResponseInfo_Hit) {
692   RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Hit);
693 }
694
695 TEST_F(AppCacheResponseTest, AmountWritten) {
696   RunTestOnIOThread(&AppCacheResponseTest::AmountWritten);
697 }
698
699 TEST_F(AppCacheResponseTest, WriteThenVariouslyReadResponse) {
700   RunTestOnIOThread(&AppCacheResponseTest::WriteThenVariouslyReadResponse);
701 }
702
703 TEST_F(AppCacheResponseTest, IOChaining) {
704   RunTestOnIOThread(&AppCacheResponseTest::IOChaining);
705 }
706
707 TEST_F(AppCacheResponseTest, DeleteWithinCallbacks) {
708   RunTestOnIOThread(&AppCacheResponseTest::DeleteWithinCallbacks);
709 }
710
711 TEST_F(AppCacheResponseTest, DeleteWithIOPending) {
712   RunTestOnIOThread(&AppCacheResponseTest::DeleteWithIOPending);
713 }
714
715 }  // namespace content