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