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.
10 #include "base/bind_helpers.h"
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/location.h"
14 #include "base/pickle.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "base/threading/thread.h"
19 #include "content/browser/appcache/appcache_response.h"
20 #include "content/browser/appcache/mock_appcache_service.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/net_errors.h"
23 #include "net/http/http_response_headers.h"
24 #include "testing/gtest/include/gtest/gtest.h"
27 using net::WrappedIOBuffer
;
31 static const int kNumBlocks
= 4;
32 static const int kBlockSize
= 1024;
33 static const int kNoSuchResponseId
= 123;
35 class AppCacheResponseTest
: public testing::Test
{
37 // Test Harness -------------------------------------------------------------
39 // Helper class used to verify test results
40 class MockStorageDelegate
: public AppCacheStorage::Delegate
{
42 explicit MockStorageDelegate(AppCacheResponseTest
* test
)
43 : loaded_info_id_(0), test_(test
) {
46 void OnResponseInfoLoaded(AppCacheResponseInfo
* info
,
47 int64 response_id
) override
{
49 loaded_info_id_
= response_id
;
50 test_
->ScheduleNextTask();
53 scoped_refptr
<AppCacheResponseInfo
> loaded_info_
;
54 int64 loaded_info_id_
;
55 AppCacheResponseTest
* test_
;
58 // Helper callback to run a test on our io_thread. The io_thread is spun up
59 // once and reused for all tests.
60 template <class Method
>
61 void MethodWrapper(Method method
) {
66 static void SetUpTestCase() {
67 io_thread_
.reset(new base::Thread("AppCacheResponseTest Thread"));
68 base::Thread::Options
options(base::MessageLoop::TYPE_IO
, 0);
69 io_thread_
->StartWithOptions(options
);
72 static void TearDownTestCase() {
73 io_thread_
.reset(NULL
);
76 AppCacheResponseTest() {}
78 template <class Method
>
79 void RunTestOnIOThread(Method method
) {
80 test_finished_event_
.reset(new base::WaitableEvent(false, false));
81 io_thread_
->task_runner()->PostTask(
82 FROM_HERE
, base::Bind(&AppCacheResponseTest::MethodWrapper
<Method
>,
83 base::Unretained(this), method
));
84 test_finished_event_
->Wait();
88 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
89 DCHECK(task_stack_
.empty());
90 storage_delegate_
.reset(new MockStorageDelegate(this));
91 service_
.reset(new MockAppCacheService());
92 expected_read_result_
= 0;
93 expected_write_result_
= 0;
94 written_response_id_
= 0;
95 should_delete_reader_in_completion_callback_
= false;
96 should_delete_writer_in_completion_callback_
= false;
97 reader_deletion_count_down_
= 0;
98 writer_deletion_count_down_
= 0;
99 read_callback_was_called_
= false;
100 write_callback_was_called_
= false;
103 void TearDownTest() {
104 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
105 while (!task_stack_
.empty())
110 read_info_buffer_
= NULL
;
112 write_buffer_
= NULL
;
113 write_info_buffer_
= NULL
;
114 storage_delegate_
.reset();
118 void TestFinished() {
119 // We unwind the stack prior to finishing up to let stack
120 // based objects get deleted.
121 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
122 base::ThreadTaskRunnerHandle::Get()->PostTask(
123 FROM_HERE
, base::Bind(&AppCacheResponseTest::TestFinishedUnwound
,
124 base::Unretained(this)));
127 void TestFinishedUnwound() {
129 test_finished_event_
->Signal();
132 void PushNextTask(const base::Closure
& task
) {
133 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, false));
136 void PushNextTaskAsImmediate(const base::Closure
& task
) {
137 task_stack_
.push(std::pair
<base::Closure
, bool>(task
, true));
140 void ScheduleNextTask() {
141 DCHECK(base::MessageLoop::current() == io_thread_
->message_loop());
142 if (task_stack_
.empty()) {
146 base::Closure task
= task_stack_
.top().first
;
147 bool immediate
= task_stack_
.top().second
;
152 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, task
);
155 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
157 void WriteBasicResponse() {
158 static const char kHttpHeaders
[] =
159 "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
160 static const char kHttpBody
[] = "Hello";
161 scoped_refptr
<IOBuffer
> body(new WrappedIOBuffer(kHttpBody
));
162 std::string
raw_headers(kHttpHeaders
, arraysize(kHttpHeaders
));
164 MakeHttpResponseInfo(raw_headers
), body
.get(), strlen(kHttpBody
));
167 int basic_response_size() { return 5; } // should match kHttpBody above
169 void WriteResponse(net::HttpResponseInfo
* head
,
170 IOBuffer
* body
, int body_len
) {
172 scoped_refptr
<IOBuffer
> body_ref(body
);
173 PushNextTask(base::Bind(&AppCacheResponseTest::WriteResponseBody
,
174 base::Unretained(this), body_ref
, body_len
));
175 WriteResponseHead(head
);
178 void WriteResponseHead(net::HttpResponseInfo
* head
) {
179 EXPECT_FALSE(writer_
->IsWritePending());
180 expected_write_result_
= GetHttpResponseInfoSize(head
);
181 write_info_buffer_
= new HttpResponseInfoIOBuffer(head
);
182 writer_
->WriteInfo(write_info_buffer_
.get(),
183 base::Bind(&AppCacheResponseTest::OnWriteInfoComplete
,
184 base::Unretained(this)));
187 void WriteResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
188 EXPECT_FALSE(writer_
->IsWritePending());
189 write_buffer_
= io_buffer
;
190 expected_write_result_
= buf_len
;
191 writer_
->WriteData(write_buffer_
.get(),
193 base::Bind(&AppCacheResponseTest::OnWriteComplete
,
194 base::Unretained(this)));
197 void WriteResponseMetadata(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
198 EXPECT_FALSE(metadata_writer_
->IsWritePending());
199 write_buffer_
= io_buffer
;
200 expected_write_result_
= buf_len
;
201 metadata_writer_
->WriteMetadata(
202 write_buffer_
.get(), buf_len
,
203 base::Bind(&AppCacheResponseTest::OnMetadataWriteComplete
,
204 base::Unretained(this)));
207 void ReadResponseBody(scoped_refptr
<IOBuffer
> io_buffer
, int buf_len
) {
208 EXPECT_FALSE(reader_
->IsReadPending());
209 read_buffer_
= io_buffer
;
210 expected_read_result_
= buf_len
;
211 reader_
->ReadData(read_buffer_
.get(),
213 base::Bind(&AppCacheResponseTest::OnReadComplete
,
214 base::Unretained(this)));
217 // AppCacheResponseReader / Writer completion callbacks
219 void OnWriteInfoComplete(int result
) {
220 EXPECT_FALSE(writer_
->IsWritePending());
221 EXPECT_EQ(expected_write_result_
, result
);
225 void OnWriteComplete(int result
) {
226 EXPECT_FALSE(writer_
->IsWritePending());
227 write_callback_was_called_
= true;
228 EXPECT_EQ(expected_write_result_
, result
);
229 if (should_delete_writer_in_completion_callback_
&&
230 --writer_deletion_count_down_
== 0) {
236 void OnMetadataWriteComplete(int result
) {
237 EXPECT_FALSE(metadata_writer_
->IsWritePending());
238 EXPECT_EQ(expected_write_result_
, result
);
242 void OnReadInfoComplete(int result
) {
243 EXPECT_FALSE(reader_
->IsReadPending());
244 EXPECT_EQ(expected_read_result_
, result
);
248 void OnReadComplete(int result
) {
249 EXPECT_FALSE(reader_
->IsReadPending());
250 read_callback_was_called_
= true;
251 EXPECT_EQ(expected_read_result_
, result
);
252 if (should_delete_reader_in_completion_callback_
&&
253 --reader_deletion_count_down_
== 0) {
259 // Helpers to work with HttpResponseInfo objects
261 net::HttpResponseInfo
* MakeHttpResponseInfo(const std::string
& raw_headers
) {
262 net::HttpResponseInfo
* info
= new net::HttpResponseInfo
;
263 info
->request_time
= base::Time::Now();
264 info
->response_time
= base::Time::Now();
265 info
->was_cached
= false;
266 info
->headers
= new net::HttpResponseHeaders(raw_headers
);
270 int GetHttpResponseInfoSize(const net::HttpResponseInfo
* info
) {
272 return PickleHttpResonseInfo(&pickle
, info
);
275 bool CompareHttpResponseInfos(const net::HttpResponseInfo
* info1
,
276 const net::HttpResponseInfo
* info2
) {
277 base::Pickle pickle1
;
278 base::Pickle pickle2
;
279 PickleHttpResonseInfo(&pickle1
, info1
);
280 PickleHttpResonseInfo(&pickle2
, info2
);
281 return (pickle1
.size() == pickle2
.size()) &&
282 (0 == memcmp(pickle1
.data(), pickle2
.data(), pickle1
.size()));
285 int PickleHttpResonseInfo(base::Pickle
* pickle
,
286 const net::HttpResponseInfo
* info
) {
287 const bool kSkipTransientHeaders
= true;
288 const bool kTruncated
= false;
289 info
->Persist(pickle
, kSkipTransientHeaders
, kTruncated
);
290 return pickle
->size();
293 // Helpers to fill and verify blocks of memory with a value
295 void FillData(char value
, char* data
, int data_len
) {
296 memset(data
, value
, data_len
);
299 bool CheckData(char value
, const char* data
, int data_len
) {
300 for (int i
= 0; i
< data_len
; ++i
, ++data
) {
307 // Individual Tests ---------------------------------------------------------
308 // Most of the individual tests involve multiple async steps. Each test
309 // is delineated with a section header.
312 // ReadNonExistentResponse -------------------------------------------
313 void ReadNonExistentResponse() {
314 // 1. Attempt to ReadInfo
315 // 2. Attempt to ReadData
317 reader_
.reset(service_
->storage()->CreateResponseReader(
318 GURL(), 0, kNoSuchResponseId
));
320 // Push tasks in reverse order
321 PushNextTask(base::Bind(&AppCacheResponseTest::ReadNonExistentData
,
322 base::Unretained(this)));
323 PushNextTask(base::Bind(&AppCacheResponseTest::ReadNonExistentInfo
,
324 base::Unretained(this)));
328 void ReadNonExistentInfo() {
329 EXPECT_FALSE(reader_
->IsReadPending());
330 read_info_buffer_
= new HttpResponseInfoIOBuffer();
331 reader_
->ReadInfo(read_info_buffer_
.get(),
332 base::Bind(&AppCacheResponseTest::OnReadInfoComplete
,
333 base::Unretained(this)));
334 EXPECT_TRUE(reader_
->IsReadPending());
335 expected_read_result_
= net::ERR_CACHE_MISS
;
338 void ReadNonExistentData() {
339 EXPECT_FALSE(reader_
->IsReadPending());
340 read_buffer_
= new IOBuffer(kBlockSize
);
341 reader_
->ReadData(read_buffer_
.get(),
343 base::Bind(&AppCacheResponseTest::OnReadComplete
,
344 base::Unretained(this)));
345 EXPECT_TRUE(reader_
->IsReadPending());
346 expected_read_result_
= net::ERR_CACHE_MISS
;
349 // LoadResponseInfo_Miss ----------------------------------------------------
350 void LoadResponseInfo_Miss() {
351 PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Miss_Verify
,
352 base::Unretained(this)));
353 service_
->storage()->LoadResponseInfo(GURL(), 0, kNoSuchResponseId
,
354 storage_delegate_
.get());
357 void LoadResponseInfo_Miss_Verify() {
358 EXPECT_EQ(kNoSuchResponseId
, storage_delegate_
->loaded_info_id_
);
359 EXPECT_TRUE(!storage_delegate_
->loaded_info_
.get());
363 // LoadResponseInfo_Hit ----------------------------------------------------
364 void LoadResponseInfo_Hit() {
365 // This tests involves multiple async steps.
366 // 1. Write a response headers and body to storage
369 // 2. Use LoadResponseInfo to read the response headers back out
370 PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Hit_Step2
,
371 base::Unretained(this)));
372 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
373 written_response_id_
= writer_
->response_id();
374 WriteBasicResponse();
377 void LoadResponseInfo_Hit_Step2() {
379 PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Hit_Verify
,
380 base::Unretained(this)));
381 service_
->storage()->LoadResponseInfo(GURL(), 0, written_response_id_
,
382 storage_delegate_
.get());
385 void LoadResponseInfo_Hit_Verify() {
386 EXPECT_EQ(written_response_id_
, storage_delegate_
->loaded_info_id_
);
387 EXPECT_TRUE(storage_delegate_
->loaded_info_
.get());
388 EXPECT_TRUE(CompareHttpResponseInfos(
389 write_info_buffer_
->http_info
.get(),
390 storage_delegate_
->loaded_info_
->http_response_info()));
391 EXPECT_EQ(basic_response_size(),
392 storage_delegate_
->loaded_info_
->response_data_size());
396 // Metadata -------------------------------------------------
398 // This tests involves multiple async steps.
399 // 1. Write a response headers and body to storage
402 // 2. Write metadata "Metadata First" using AppCacheResponseMetadataWriter.
403 // 3. Check metadata was written.
404 // 4. Write metadata "Second".
405 // 5. Check metadata was written and was truncated .
406 // 6. Write metadata "".
407 // 7. Check metadata was deleted.
409 // Push tasks in reverse order.
410 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata
,
411 base::Unretained(this), ""));
412 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo
,
413 base::Unretained(this)));
414 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata
,
415 base::Unretained(this), ""));
416 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata
,
417 base::Unretained(this), "Second"));
418 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo
,
419 base::Unretained(this)));
420 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata
,
421 base::Unretained(this), "Second"));
422 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata
,
423 base::Unretained(this), "Metadata First"));
424 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo
,
425 base::Unretained(this)));
426 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata
,
427 base::Unretained(this), "Metadata First"));
428 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_ResetWriter
,
429 base::Unretained(this)));
430 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
431 written_response_id_
= writer_
->response_id();
432 WriteBasicResponse();
435 void Metadata_ResetWriter() {
440 void Metadata_WriteMetadata(const char* metadata
) {
441 metadata_writer_
.reset(service_
->storage()->CreateResponseMetadataWriter(
442 0, written_response_id_
));
443 scoped_refptr
<IOBuffer
> buffer(new WrappedIOBuffer(metadata
));
444 WriteResponseMetadata(buffer
.get(), strlen(metadata
));
447 void Metadata_LoadResponseInfo() {
448 metadata_writer_
.reset();
449 storage_delegate_
.reset(new MockStorageDelegate(this));
450 service_
->storage()->LoadResponseInfo(GURL(), 0, written_response_id_
,
451 storage_delegate_
.get());
454 void Metadata_VerifyMetadata(const char* metadata
) {
455 EXPECT_EQ(written_response_id_
, storage_delegate_
->loaded_info_id_
);
456 EXPECT_TRUE(storage_delegate_
->loaded_info_
.get());
457 const net::HttpResponseInfo
* read_head
=
458 storage_delegate_
->loaded_info_
->http_response_info();
459 EXPECT_TRUE(read_head
);
460 const int metadata_size
= strlen(metadata
);
462 EXPECT_TRUE(read_head
->metadata
.get());
463 EXPECT_EQ(metadata_size
, read_head
->metadata
->size());
465 memcmp(metadata
, read_head
->metadata
->data(), metadata_size
));
467 EXPECT_FALSE(read_head
->metadata
.get());
469 EXPECT_TRUE(CompareHttpResponseInfos(
470 write_info_buffer_
->http_info
.get(),
471 storage_delegate_
->loaded_info_
->http_response_info()));
472 EXPECT_EQ(basic_response_size(),
473 storage_delegate_
->loaded_info_
->response_data_size());
477 // AmountWritten ----------------------------------------------------
479 void AmountWritten() {
480 static const char kHttpHeaders
[] = "HTTP/1.0 200 OK\0\0";
481 std::string
raw_headers(kHttpHeaders
, arraysize(kHttpHeaders
));
482 net::HttpResponseInfo
* head
= MakeHttpResponseInfo(raw_headers
);
483 int expected_amount_written
=
484 GetHttpResponseInfoSize(head
) + kNumBlocks
* kBlockSize
;
486 // Push tasks in reverse order.
487 PushNextTask(base::Bind(&AppCacheResponseTest::Verify_AmountWritten
,
488 base::Unretained(this), expected_amount_written
));
489 for (int i
= 0; i
< kNumBlocks
; ++i
) {
490 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOneBlock
,
491 base::Unretained(this), kNumBlocks
- i
));
493 PushNextTask(base::Bind(&AppCacheResponseTest::WriteResponseHead
,
494 base::Unretained(this), head
));
496 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
497 written_response_id_
= writer_
->response_id();
501 void Verify_AmountWritten(int expected_amount_written
) {
502 EXPECT_EQ(expected_amount_written
, writer_
->amount_written());
507 // WriteThenVariouslyReadResponse -------------------------------------------
509 void WriteThenVariouslyReadResponse() {
510 // This tests involves multiple async steps.
511 // 1. First, write a large body using multiple writes, we don't bother
512 // with a response head for this test.
513 // 2. Read the entire body, using multiple reads
514 // 3. Read the entire body, using one read.
515 // 4. Attempt to read beyond the EOF.
516 // 5. Read just a range.
517 // 6. Attempt to read beyond EOF of a range.
519 // Push tasks in reverse order
520 PushNextTask(base::Bind(&AppCacheResponseTest::ReadRangeFullyBeyondEOF
,
521 base::Unretained(this)));
522 PushNextTask(base::Bind(&AppCacheResponseTest::ReadRangePartiallyBeyondEOF
,
523 base::Unretained(this)));
524 PushNextTask(base::Bind(&AppCacheResponseTest::ReadPastEOF
,
525 base::Unretained(this)));
526 PushNextTask(base::Bind(&AppCacheResponseTest::ReadRange
,
527 base::Unretained(this)));
528 PushNextTask(base::Bind(&AppCacheResponseTest::ReadPastEOF
,
529 base::Unretained(this)));
530 PushNextTask(base::Bind(&AppCacheResponseTest::ReadAllAtOnce
,
531 base::Unretained(this)));
532 PushNextTask(base::Bind(&AppCacheResponseTest::ReadInBlocks
,
533 base::Unretained(this)));
534 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks
,
535 base::Unretained(this)));
541 void WriteOutBlocks() {
542 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
543 written_response_id_
= writer_
->response_id();
544 for (int i
= 0; i
< kNumBlocks
; ++i
) {
545 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOneBlock
,
546 base::Unretained(this), kNumBlocks
- i
));
551 void WriteOneBlock(int block_number
) {
552 scoped_refptr
<IOBuffer
> io_buffer(
553 new IOBuffer(kBlockSize
));
554 FillData(block_number
, io_buffer
->data(), kBlockSize
);
555 WriteResponseBody(io_buffer
, kBlockSize
);
558 void ReadInBlocks() {
560 reader_
.reset(service_
->storage()->CreateResponseReader(
561 GURL(), 0, written_response_id_
));
562 for (int i
= 0; i
< kNumBlocks
; ++i
) {
563 PushNextTask(base::Bind(&AppCacheResponseTest::ReadOneBlock
,
564 base::Unretained(this), kNumBlocks
- i
));
569 void ReadOneBlock(int block_number
) {
570 PushNextTask(base::Bind(&AppCacheResponseTest::VerifyOneBlock
,
571 base::Unretained(this), block_number
));
572 ReadResponseBody(new IOBuffer(kBlockSize
), kBlockSize
);
575 void VerifyOneBlock(int block_number
) {
576 EXPECT_TRUE(CheckData(block_number
, read_buffer_
->data(), kBlockSize
));
580 void ReadAllAtOnce() {
581 PushNextTask(base::Bind(&AppCacheResponseTest::VerifyAllAtOnce
,
582 base::Unretained(this)));
583 reader_
.reset(service_
->storage()->CreateResponseReader(
584 GURL(), 0, written_response_id_
));
585 int big_size
= kNumBlocks
* kBlockSize
;
586 ReadResponseBody(new IOBuffer(big_size
), big_size
);
589 void VerifyAllAtOnce() {
590 char* p
= read_buffer_
->data();
591 for (int i
= 0; i
< kNumBlocks
; ++i
, p
+= kBlockSize
)
592 EXPECT_TRUE(CheckData(i
+ 1, p
, kBlockSize
));
597 EXPECT_FALSE(reader_
->IsReadPending());
598 read_buffer_
= new IOBuffer(kBlockSize
);
599 expected_read_result_
= 0;
600 reader_
->ReadData(read_buffer_
.get(),
602 base::Bind(&AppCacheResponseTest::OnReadComplete
,
603 base::Unretained(this)));
607 PushNextTask(base::Bind(&AppCacheResponseTest::VerifyRange
,
608 base::Unretained(this)));
609 reader_
.reset(service_
->storage()->CreateResponseReader(
610 GURL(), 0, written_response_id_
));
611 reader_
->SetReadRange(kBlockSize
, kBlockSize
);
612 ReadResponseBody(new IOBuffer(kBlockSize
), kBlockSize
);
616 EXPECT_TRUE(CheckData(2, read_buffer_
->data(), kBlockSize
));
617 ScheduleNextTask(); // ReadPastEOF is scheduled next
620 void ReadRangePartiallyBeyondEOF() {
621 PushNextTask(base::Bind(&AppCacheResponseTest::VerifyRangeBeyondEOF
,
622 base::Unretained(this)));
623 reader_
.reset(service_
->storage()->CreateResponseReader(
624 GURL(), 0, written_response_id_
));
625 reader_
->SetReadRange(kBlockSize
, kNumBlocks
* kBlockSize
);
626 ReadResponseBody(new IOBuffer(kNumBlocks
* kBlockSize
),
627 kNumBlocks
* kBlockSize
);
628 expected_read_result_
= (kNumBlocks
- 1) * kBlockSize
;
631 void VerifyRangeBeyondEOF() {
632 // Just verify the first 1k
636 void ReadRangeFullyBeyondEOF() {
637 reader_
.reset(service_
->storage()->CreateResponseReader(
638 GURL(), 0, written_response_id_
));
639 reader_
->SetReadRange((kNumBlocks
* kBlockSize
) + 1, kBlockSize
);
640 ReadResponseBody(new IOBuffer(kBlockSize
), kBlockSize
);
641 expected_read_result_
= 0;
644 // IOChaining -------------------------------------------
646 // 1. Write several blocks out initiating the subsequent write
647 // from within the completion callback of the previous write.
648 // 2. Read and verify several blocks in similarly chaining reads.
650 // Push tasks in reverse order
651 PushNextTaskAsImmediate(
652 base::Bind(&AppCacheResponseTest::ReadInBlocksImmediately
,
653 base::Unretained(this)));
654 PushNextTaskAsImmediate(
655 base::Bind(&AppCacheResponseTest::WriteOutBlocksImmediately
,
656 base::Unretained(this)));
662 void WriteOutBlocksImmediately() {
663 writer_
.reset(service_
->storage()->CreateResponseWriter(GURL(), 0));
664 written_response_id_
= writer_
->response_id();
665 for (int i
= 0; i
< kNumBlocks
; ++i
) {
666 PushNextTaskAsImmediate(
667 base::Bind(&AppCacheResponseTest::WriteOneBlock
,
668 base::Unretained(this), kNumBlocks
- i
));
673 void ReadInBlocksImmediately() {
675 reader_
.reset(service_
->storage()->CreateResponseReader(
676 GURL(), 0, written_response_id_
));
677 for (int i
= 0; i
< kNumBlocks
; ++i
) {
678 PushNextTaskAsImmediate(
679 base::Bind(&AppCacheResponseTest::ReadOneBlockImmediately
,
680 base::Unretained(this),
686 void ReadOneBlockImmediately(int block_number
) {
687 PushNextTaskAsImmediate(base::Bind(&AppCacheResponseTest::VerifyOneBlock
,
688 base::Unretained(this), block_number
));
689 ReadResponseBody(new IOBuffer(kBlockSize
), kBlockSize
);
692 // DeleteWithinCallbacks -------------------------------------------
693 void DeleteWithinCallbacks() {
694 // 1. Write out a few blocks normally, and upon
695 // completion of the last write, delete the writer.
696 // 2. Read in a few blocks normally, and upon completion
697 // of the last read, delete the reader.
699 should_delete_reader_in_completion_callback_
= true;
700 reader_deletion_count_down_
= kNumBlocks
;
701 should_delete_writer_in_completion_callback_
= true;
702 writer_deletion_count_down_
= kNumBlocks
;
704 PushNextTask(base::Bind(&AppCacheResponseTest::ReadInBlocks
,
705 base::Unretained(this)));
706 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks
,
707 base::Unretained(this)));
711 // DeleteWithIOPending -------------------------------------------
712 void DeleteWithIOPending() {
713 // 1. Write a few blocks normally.
714 // 2. Start a write, delete with it pending.
715 // 3. Start a read, delete with it pending.
716 PushNextTask(base::Bind(&AppCacheResponseTest::ReadThenDelete
,
717 base::Unretained(this)));
718 PushNextTask(base::Bind(&AppCacheResponseTest::WriteThenDelete
,
719 base::Unretained(this)));
720 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks
,
721 base::Unretained(this)));
725 void WriteThenDelete() {
726 write_callback_was_called_
= false;
728 EXPECT_TRUE(writer_
->IsWritePending());
733 void ReadThenDelete() {
734 read_callback_was_called_
= false;
735 reader_
.reset(service_
->storage()->CreateResponseReader(
736 GURL(), 0, written_response_id_
));
737 ReadResponseBody(new IOBuffer(kBlockSize
), kBlockSize
);
738 EXPECT_TRUE(reader_
->IsReadPending());
741 // Wait a moment to verify no callbacks.
742 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
743 FROM_HERE
, base::Bind(&AppCacheResponseTest::VerifyNoCallbacks
,
744 base::Unretained(this)),
745 base::TimeDelta::FromMilliseconds(10));
748 void VerifyNoCallbacks() {
749 EXPECT_TRUE(!write_callback_was_called_
);
750 EXPECT_TRUE(!read_callback_was_called_
);
756 scoped_ptr
<base::WaitableEvent
> test_finished_event_
;
757 scoped_ptr
<MockStorageDelegate
> storage_delegate_
;
758 scoped_ptr
<MockAppCacheService
> service_
;
759 std::stack
<std::pair
<base::Closure
, bool> > task_stack_
;
761 scoped_ptr
<AppCacheResponseReader
> reader_
;
762 scoped_refptr
<HttpResponseInfoIOBuffer
> read_info_buffer_
;
763 scoped_refptr
<IOBuffer
> read_buffer_
;
764 int expected_read_result_
;
765 bool should_delete_reader_in_completion_callback_
;
766 int reader_deletion_count_down_
;
767 bool read_callback_was_called_
;
769 int64 written_response_id_
;
770 scoped_ptr
<AppCacheResponseWriter
> writer_
;
771 scoped_ptr
<AppCacheResponseMetadataWriter
> metadata_writer_
;
772 scoped_refptr
<HttpResponseInfoIOBuffer
> write_info_buffer_
;
773 scoped_refptr
<IOBuffer
> write_buffer_
;
774 int expected_write_result_
;
775 bool should_delete_writer_in_completion_callback_
;
776 int writer_deletion_count_down_
;
777 bool write_callback_was_called_
;
779 static scoped_ptr
<base::Thread
> io_thread_
;
783 scoped_ptr
<base::Thread
> AppCacheResponseTest::io_thread_
;
785 TEST_F(AppCacheResponseTest
, ReadNonExistentResponse
) {
786 RunTestOnIOThread(&AppCacheResponseTest::ReadNonExistentResponse
);
789 TEST_F(AppCacheResponseTest
, LoadResponseInfo_Miss
) {
790 RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Miss
);
793 TEST_F(AppCacheResponseTest
, LoadResponseInfo_Hit
) {
794 RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Hit
);
797 TEST_F(AppCacheResponseTest
, Metadata
) {
798 RunTestOnIOThread(&AppCacheResponseTest::Metadata
);
801 TEST_F(AppCacheResponseTest
, AmountWritten
) {
802 RunTestOnIOThread(&AppCacheResponseTest::AmountWritten
);
805 TEST_F(AppCacheResponseTest
, WriteThenVariouslyReadResponse
) {
806 RunTestOnIOThread(&AppCacheResponseTest::WriteThenVariouslyReadResponse
);
809 TEST_F(AppCacheResponseTest
, IOChaining
) {
810 RunTestOnIOThread(&AppCacheResponseTest::IOChaining
);
813 TEST_F(AppCacheResponseTest
, DeleteWithinCallbacks
) {
814 RunTestOnIOThread(&AppCacheResponseTest::DeleteWithinCallbacks
);
817 TEST_F(AppCacheResponseTest
, DeleteWithIOPending
) {
818 RunTestOnIOThread(&AppCacheResponseTest::DeleteWithIOPending
);
821 } // namespace content