Home | History | Annotate | Download | only in appcache
      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
    716