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
23using net::IOBuffer;
24using net::WrappedIOBuffer;
25
26namespace appcache {
27
28static const int kNumBlocks = 4;
29static const int kBlockSize = 1024;
30static const int kNoSuchResponseId = 123;
31
32class 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
683scoped_ptr<base::Thread> AppCacheResponseTest::io_thread_;
684
685TEST_F(AppCacheResponseTest, ReadNonExistentResponse) {
686  RunTestOnIOThread(&AppCacheResponseTest::ReadNonExistentResponse);
687}
688
689TEST_F(AppCacheResponseTest, LoadResponseInfo_Miss) {
690  RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Miss);
691}
692
693TEST_F(AppCacheResponseTest, LoadResponseInfo_Hit) {
694  RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Hit);
695}
696
697TEST_F(AppCacheResponseTest, AmountWritten) {
698  RunTestOnIOThread(&AppCacheResponseTest::AmountWritten);
699}
700
701TEST_F(AppCacheResponseTest, WriteThenVariouslyReadResponse) {
702  RunTestOnIOThread(&AppCacheResponseTest::WriteThenVariouslyReadResponse);
703}
704
705TEST_F(AppCacheResponseTest, IOChaining) {
706  RunTestOnIOThread(&AppCacheResponseTest::IOChaining);
707}
708
709TEST_F(AppCacheResponseTest, DeleteWithinCallbacks) {
710  RunTestOnIOThread(&AppCacheResponseTest::DeleteWithinCallbacks);
711}
712
713TEST_F(AppCacheResponseTest, DeleteWithIOPending) {
714  RunTestOnIOThread(&AppCacheResponseTest::DeleteWithIOPending);
715}
716
717}  // namespace appcache
718