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
23using net::IOBuffer;
24using net::WrappedIOBuffer;
25
26namespace content {
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  // 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
681scoped_ptr<base::Thread> AppCacheResponseTest::io_thread_;
682
683TEST_F(AppCacheResponseTest, ReadNonExistentResponse) {
684  RunTestOnIOThread(&AppCacheResponseTest::ReadNonExistentResponse);
685}
686
687TEST_F(AppCacheResponseTest, LoadResponseInfo_Miss) {
688  RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Miss);
689}
690
691TEST_F(AppCacheResponseTest, LoadResponseInfo_Hit) {
692  RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Hit);
693}
694
695TEST_F(AppCacheResponseTest, AmountWritten) {
696  RunTestOnIOThread(&AppCacheResponseTest::AmountWritten);
697}
698
699TEST_F(AppCacheResponseTest, WriteThenVariouslyReadResponse) {
700  RunTestOnIOThread(&AppCacheResponseTest::WriteThenVariouslyReadResponse);
701}
702
703TEST_F(AppCacheResponseTest, IOChaining) {
704  RunTestOnIOThread(&AppCacheResponseTest::IOChaining);
705}
706
707TEST_F(AppCacheResponseTest, DeleteWithinCallbacks) {
708  RunTestOnIOThread(&AppCacheResponseTest::DeleteWithinCallbacks);
709}
710
711TEST_F(AppCacheResponseTest, DeleteWithIOPending) {
712  RunTestOnIOThread(&AppCacheResponseTest::DeleteWithIOPending);
713}
714
715}  // namespace content
716