Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / appcache / appcache_response_unittest.cc
blob5f91f92fbd2eb3452f9c8de15c8b535480af5027
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.
5 #include <stack>
6 #include <string>
7 #include <utility>
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"
23 using net::IOBuffer;
24 using net::WrappedIOBuffer;
26 namespace content {
28 static const int kNumBlocks = 4;
29 static const int kBlockSize = 1024;
30 static const int kNoSuchResponseId = 123;
32 class AppCacheResponseTest : public testing::Test {
33 public:
34 // Test Harness -------------------------------------------------------------
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) {
43 void OnResponseInfoLoaded(AppCacheResponseInfo* info,
44 int64 response_id) override {
45 loaded_info_ = info;
46 loaded_info_id_ = response_id;
47 test_->ScheduleNextTask();
50 scoped_refptr<AppCacheResponseInfo> loaded_info_;
51 int64 loaded_info_id_;
52 AppCacheResponseTest* test_;
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)();
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);
69 static void TearDownTestCase() {
70 io_thread_.reset(NULL);
73 AppCacheResponseTest() {}
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();
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;
100 void TearDownTest() {
101 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
102 while (!task_stack_.empty())
103 task_stack_.pop();
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();
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)));
124 void TestFinishedUnwound() {
125 TearDownTest();
126 test_finished_event_->Signal();
129 void PushNextTask(const base::Closure& task) {
130 task_stack_.push(std::pair<base::Closure, bool>(task, false));
133 void PushNextTaskAsImmediate(const base::Closure& task) {
134 task_stack_.push(std::pair<base::Closure, bool>(task, true));
137 void ScheduleNextTask() {
138 DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
139 if (task_stack_.empty()) {
140 TestFinished();
141 return;
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);
152 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
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));
164 int basic_response_size() { return 5; } // should match kHttpBody above
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);
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)));
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)));
194 void WriteResponseMetadata(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
195 EXPECT_FALSE(metadata_writer_->IsWritePending());
196 write_buffer_ = io_buffer;
197 expected_write_result_ = buf_len;
198 metadata_writer_->WriteMetadata(
199 write_buffer_.get(), buf_len,
200 base::Bind(&AppCacheResponseTest::OnMetadataWriteComplete,
201 base::Unretained(this)));
204 void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
205 EXPECT_FALSE(reader_->IsReadPending());
206 read_buffer_ = io_buffer;
207 expected_read_result_ = buf_len;
208 reader_->ReadData(read_buffer_.get(),
209 buf_len,
210 base::Bind(&AppCacheResponseTest::OnReadComplete,
211 base::Unretained(this)));
214 // AppCacheResponseReader / Writer completion callbacks
216 void OnWriteInfoComplete(int result) {
217 EXPECT_FALSE(writer_->IsWritePending());
218 EXPECT_EQ(expected_write_result_, result);
219 ScheduleNextTask();
222 void OnWriteComplete(int result) {
223 EXPECT_FALSE(writer_->IsWritePending());
224 write_callback_was_called_ = true;
225 EXPECT_EQ(expected_write_result_, result);
226 if (should_delete_writer_in_completion_callback_ &&
227 --writer_deletion_count_down_ == 0) {
228 writer_.reset();
230 ScheduleNextTask();
233 void OnMetadataWriteComplete(int result) {
234 EXPECT_FALSE(metadata_writer_->IsWritePending());
235 EXPECT_EQ(expected_write_result_, result);
236 ScheduleNextTask();
239 void OnReadInfoComplete(int result) {
240 EXPECT_FALSE(reader_->IsReadPending());
241 EXPECT_EQ(expected_read_result_, result);
242 ScheduleNextTask();
245 void OnReadComplete(int result) {
246 EXPECT_FALSE(reader_->IsReadPending());
247 read_callback_was_called_ = true;
248 EXPECT_EQ(expected_read_result_, result);
249 if (should_delete_reader_in_completion_callback_ &&
250 --reader_deletion_count_down_ == 0) {
251 reader_.reset();
253 ScheduleNextTask();
256 // Helpers to work with HttpResponseInfo objects
258 net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
259 net::HttpResponseInfo* info = new net::HttpResponseInfo;
260 info->request_time = base::Time::Now();
261 info->response_time = base::Time::Now();
262 info->was_cached = false;
263 info->headers = new net::HttpResponseHeaders(raw_headers);
264 return info;
267 int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
268 Pickle pickle;
269 return PickleHttpResonseInfo(&pickle, info);
272 bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
273 const net::HttpResponseInfo* info2) {
274 Pickle pickle1;
275 Pickle pickle2;
276 PickleHttpResonseInfo(&pickle1, info1);
277 PickleHttpResonseInfo(&pickle2, info2);
278 return (pickle1.size() == pickle2.size()) &&
279 (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
282 int PickleHttpResonseInfo(Pickle* pickle, const net::HttpResponseInfo* info) {
283 const bool kSkipTransientHeaders = true;
284 const bool kTruncated = false;
285 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
286 return pickle->size();
289 // Helpers to fill and verify blocks of memory with a value
291 void FillData(char value, char* data, int data_len) {
292 memset(data, value, data_len);
295 bool CheckData(char value, const char* data, int data_len) {
296 for (int i = 0; i < data_len; ++i, ++data) {
297 if (*data != value)
298 return false;
300 return true;
303 // Individual Tests ---------------------------------------------------------
304 // Most of the individual tests involve multiple async steps. Each test
305 // is delineated with a section header.
308 // ReadNonExistentResponse -------------------------------------------
309 void ReadNonExistentResponse() {
310 // 1. Attempt to ReadInfo
311 // 2. Attempt to ReadData
313 reader_.reset(service_->storage()->CreateResponseReader(
314 GURL(), 0, kNoSuchResponseId));
316 // Push tasks in reverse order
317 PushNextTask(base::Bind(&AppCacheResponseTest::ReadNonExistentData,
318 base::Unretained(this)));
319 PushNextTask(base::Bind(&AppCacheResponseTest::ReadNonExistentInfo,
320 base::Unretained(this)));
321 ScheduleNextTask();
324 void ReadNonExistentInfo() {
325 EXPECT_FALSE(reader_->IsReadPending());
326 read_info_buffer_ = new HttpResponseInfoIOBuffer();
327 reader_->ReadInfo(read_info_buffer_.get(),
328 base::Bind(&AppCacheResponseTest::OnReadInfoComplete,
329 base::Unretained(this)));
330 EXPECT_TRUE(reader_->IsReadPending());
331 expected_read_result_ = net::ERR_CACHE_MISS;
334 void ReadNonExistentData() {
335 EXPECT_FALSE(reader_->IsReadPending());
336 read_buffer_ = new IOBuffer(kBlockSize);
337 reader_->ReadData(read_buffer_.get(),
338 kBlockSize,
339 base::Bind(&AppCacheResponseTest::OnReadComplete,
340 base::Unretained(this)));
341 EXPECT_TRUE(reader_->IsReadPending());
342 expected_read_result_ = net::ERR_CACHE_MISS;
345 // LoadResponseInfo_Miss ----------------------------------------------------
346 void LoadResponseInfo_Miss() {
347 PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Miss_Verify,
348 base::Unretained(this)));
349 service_->storage()->LoadResponseInfo(GURL(), 0, kNoSuchResponseId,
350 storage_delegate_.get());
353 void LoadResponseInfo_Miss_Verify() {
354 EXPECT_EQ(kNoSuchResponseId, storage_delegate_->loaded_info_id_);
355 EXPECT_TRUE(!storage_delegate_->loaded_info_.get());
356 TestFinished();
359 // LoadResponseInfo_Hit ----------------------------------------------------
360 void LoadResponseInfo_Hit() {
361 // This tests involves multiple async steps.
362 // 1. Write a response headers and body to storage
363 // a. headers
364 // b. body
365 // 2. Use LoadResponseInfo to read the response headers back out
366 PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Hit_Step2,
367 base::Unretained(this)));
368 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
369 written_response_id_ = writer_->response_id();
370 WriteBasicResponse();
373 void LoadResponseInfo_Hit_Step2() {
374 writer_.reset();
375 PushNextTask(base::Bind(&AppCacheResponseTest::LoadResponseInfo_Hit_Verify,
376 base::Unretained(this)));
377 service_->storage()->LoadResponseInfo(GURL(), 0, written_response_id_,
378 storage_delegate_.get());
381 void LoadResponseInfo_Hit_Verify() {
382 EXPECT_EQ(written_response_id_, storage_delegate_->loaded_info_id_);
383 EXPECT_TRUE(storage_delegate_->loaded_info_.get());
384 EXPECT_TRUE(CompareHttpResponseInfos(
385 write_info_buffer_->http_info.get(),
386 storage_delegate_->loaded_info_->http_response_info()));
387 EXPECT_EQ(basic_response_size(),
388 storage_delegate_->loaded_info_->response_data_size());
389 TestFinished();
392 // Metadata -------------------------------------------------
393 void Metadata() {
394 // This tests involves multiple async steps.
395 // 1. Write a response headers and body to storage
396 // a. headers
397 // b. body
398 // 2. Write metadata "Metadata First" using AppCacheResponseMetadataWriter.
399 // 3. Check metadata was written.
400 // 4. Write metadata "Second".
401 // 5. Check metadata was written and was truncated .
402 // 6. Write metadata "".
403 // 7. Check metadata was deleted.
405 // Push tasks in reverse order.
406 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata,
407 base::Unretained(this), ""));
408 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo,
409 base::Unretained(this)));
410 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata,
411 base::Unretained(this), ""));
412 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata,
413 base::Unretained(this), "Second"));
414 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo,
415 base::Unretained(this)));
416 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata,
417 base::Unretained(this), "Second"));
418 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_VerifyMetadata,
419 base::Unretained(this), "Metadata First"));
420 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_LoadResponseInfo,
421 base::Unretained(this)));
422 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_WriteMetadata,
423 base::Unretained(this), "Metadata First"));
424 PushNextTask(base::Bind(&AppCacheResponseTest::Metadata_ResetWriter,
425 base::Unretained(this)));
426 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
427 written_response_id_ = writer_->response_id();
428 WriteBasicResponse();
431 void Metadata_ResetWriter() {
432 writer_.reset();
433 ScheduleNextTask();
436 void Metadata_WriteMetadata(const char* metadata) {
437 metadata_writer_.reset(service_->storage()->CreateResponseMetadataWriter(
438 0, written_response_id_));
439 scoped_refptr<IOBuffer> buffer(new WrappedIOBuffer(metadata));
440 WriteResponseMetadata(buffer.get(), strlen(metadata));
443 void Metadata_LoadResponseInfo() {
444 metadata_writer_.reset();
445 storage_delegate_.reset(new MockStorageDelegate(this));
446 service_->storage()->LoadResponseInfo(GURL(), 0, written_response_id_,
447 storage_delegate_.get());
450 void Metadata_VerifyMetadata(const char* metadata) {
451 EXPECT_EQ(written_response_id_, storage_delegate_->loaded_info_id_);
452 EXPECT_TRUE(storage_delegate_->loaded_info_.get());
453 const net::HttpResponseInfo* read_head =
454 storage_delegate_->loaded_info_->http_response_info();
455 EXPECT_TRUE(read_head);
456 const int metadata_size = strlen(metadata);
457 if (metadata_size) {
458 EXPECT_TRUE(read_head->metadata.get());
459 EXPECT_EQ(metadata_size, read_head->metadata->size());
460 EXPECT_EQ(0,
461 memcmp(metadata, read_head->metadata->data(), metadata_size));
462 } else {
463 EXPECT_FALSE(read_head->metadata.get());
465 EXPECT_TRUE(CompareHttpResponseInfos(
466 write_info_buffer_->http_info.get(),
467 storage_delegate_->loaded_info_->http_response_info()));
468 EXPECT_EQ(basic_response_size(),
469 storage_delegate_->loaded_info_->response_data_size());
470 ScheduleNextTask();
473 // AmountWritten ----------------------------------------------------
475 void AmountWritten() {
476 static const char kHttpHeaders[] = "HTTP/1.0 200 OK\0\0";
477 std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
478 net::HttpResponseInfo* head = MakeHttpResponseInfo(raw_headers);
479 int expected_amount_written =
480 GetHttpResponseInfoSize(head) + kNumBlocks * kBlockSize;
482 // Push tasks in reverse order.
483 PushNextTask(base::Bind(&AppCacheResponseTest::Verify_AmountWritten,
484 base::Unretained(this), expected_amount_written));
485 for (int i = 0; i < kNumBlocks; ++i) {
486 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOneBlock,
487 base::Unretained(this), kNumBlocks - i));
489 PushNextTask(base::Bind(&AppCacheResponseTest::WriteResponseHead,
490 base::Unretained(this), head));
492 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
493 written_response_id_ = writer_->response_id();
494 ScheduleNextTask();
497 void Verify_AmountWritten(int expected_amount_written) {
498 EXPECT_EQ(expected_amount_written, writer_->amount_written());
499 TestFinished();
503 // WriteThenVariouslyReadResponse -------------------------------------------
505 void WriteThenVariouslyReadResponse() {
506 // This tests involves multiple async steps.
507 // 1. First, write a large body using multiple writes, we don't bother
508 // with a response head for this test.
509 // 2. Read the entire body, using multiple reads
510 // 3. Read the entire body, using one read.
511 // 4. Attempt to read beyond the EOF.
512 // 5. Read just a range.
513 // 6. Attempt to read beyond EOF of a range.
515 // Push tasks in reverse order
516 PushNextTask(base::Bind(&AppCacheResponseTest::ReadRangeFullyBeyondEOF,
517 base::Unretained(this)));
518 PushNextTask(base::Bind(&AppCacheResponseTest::ReadRangePartiallyBeyondEOF,
519 base::Unretained(this)));
520 PushNextTask(base::Bind(&AppCacheResponseTest::ReadPastEOF,
521 base::Unretained(this)));
522 PushNextTask(base::Bind(&AppCacheResponseTest::ReadRange,
523 base::Unretained(this)));
524 PushNextTask(base::Bind(&AppCacheResponseTest::ReadPastEOF,
525 base::Unretained(this)));
526 PushNextTask(base::Bind(&AppCacheResponseTest::ReadAllAtOnce,
527 base::Unretained(this)));
528 PushNextTask(base::Bind(&AppCacheResponseTest::ReadInBlocks,
529 base::Unretained(this)));
530 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks,
531 base::Unretained(this)));
533 // Get them going.
534 ScheduleNextTask();
537 void WriteOutBlocks() {
538 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
539 written_response_id_ = writer_->response_id();
540 for (int i = 0; i < kNumBlocks; ++i) {
541 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOneBlock,
542 base::Unretained(this), kNumBlocks - i));
544 ScheduleNextTask();
547 void WriteOneBlock(int block_number) {
548 scoped_refptr<IOBuffer> io_buffer(
549 new IOBuffer(kBlockSize));
550 FillData(block_number, io_buffer->data(), kBlockSize);
551 WriteResponseBody(io_buffer, kBlockSize);
554 void ReadInBlocks() {
555 writer_.reset();
556 reader_.reset(service_->storage()->CreateResponseReader(
557 GURL(), 0, written_response_id_));
558 for (int i = 0; i < kNumBlocks; ++i) {
559 PushNextTask(base::Bind(&AppCacheResponseTest::ReadOneBlock,
560 base::Unretained(this), kNumBlocks - i));
562 ScheduleNextTask();
565 void ReadOneBlock(int block_number) {
566 PushNextTask(base::Bind(&AppCacheResponseTest::VerifyOneBlock,
567 base::Unretained(this), block_number));
568 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
571 void VerifyOneBlock(int block_number) {
572 EXPECT_TRUE(CheckData(block_number, read_buffer_->data(), kBlockSize));
573 ScheduleNextTask();
576 void ReadAllAtOnce() {
577 PushNextTask(base::Bind(&AppCacheResponseTest::VerifyAllAtOnce,
578 base::Unretained(this)));
579 reader_.reset(service_->storage()->CreateResponseReader(
580 GURL(), 0, written_response_id_));
581 int big_size = kNumBlocks * kBlockSize;
582 ReadResponseBody(new IOBuffer(big_size), big_size);
585 void VerifyAllAtOnce() {
586 char* p = read_buffer_->data();
587 for (int i = 0; i < kNumBlocks; ++i, p += kBlockSize)
588 EXPECT_TRUE(CheckData(i + 1, p, kBlockSize));
589 ScheduleNextTask();
592 void ReadPastEOF() {
593 EXPECT_FALSE(reader_->IsReadPending());
594 read_buffer_ = new IOBuffer(kBlockSize);
595 expected_read_result_ = 0;
596 reader_->ReadData(read_buffer_.get(),
597 kBlockSize,
598 base::Bind(&AppCacheResponseTest::OnReadComplete,
599 base::Unretained(this)));
602 void ReadRange() {
603 PushNextTask(base::Bind(&AppCacheResponseTest::VerifyRange,
604 base::Unretained(this)));
605 reader_.reset(service_->storage()->CreateResponseReader(
606 GURL(), 0, written_response_id_));
607 reader_->SetReadRange(kBlockSize, kBlockSize);
608 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
611 void VerifyRange() {
612 EXPECT_TRUE(CheckData(2, read_buffer_->data(), kBlockSize));
613 ScheduleNextTask(); // ReadPastEOF is scheduled next
616 void ReadRangePartiallyBeyondEOF() {
617 PushNextTask(base::Bind(&AppCacheResponseTest::VerifyRangeBeyondEOF,
618 base::Unretained(this)));
619 reader_.reset(service_->storage()->CreateResponseReader(
620 GURL(), 0, written_response_id_));
621 reader_->SetReadRange(kBlockSize, kNumBlocks * kBlockSize);
622 ReadResponseBody(new IOBuffer(kNumBlocks * kBlockSize),
623 kNumBlocks * kBlockSize);
624 expected_read_result_ = (kNumBlocks - 1) * kBlockSize;
627 void VerifyRangeBeyondEOF() {
628 // Just verify the first 1k
629 VerifyRange();
632 void ReadRangeFullyBeyondEOF() {
633 reader_.reset(service_->storage()->CreateResponseReader(
634 GURL(), 0, written_response_id_));
635 reader_->SetReadRange((kNumBlocks * kBlockSize) + 1, kBlockSize);
636 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
637 expected_read_result_ = 0;
640 // IOChaining -------------------------------------------
641 void IOChaining() {
642 // 1. Write several blocks out initiating the subsequent write
643 // from within the completion callback of the previous write.
644 // 2. Read and verify several blocks in similarly chaining reads.
646 // Push tasks in reverse order
647 PushNextTaskAsImmediate(
648 base::Bind(&AppCacheResponseTest::ReadInBlocksImmediately,
649 base::Unretained(this)));
650 PushNextTaskAsImmediate(
651 base::Bind(&AppCacheResponseTest::WriteOutBlocksImmediately,
652 base::Unretained(this)));
654 // Get them going.
655 ScheduleNextTask();
658 void WriteOutBlocksImmediately() {
659 writer_.reset(service_->storage()->CreateResponseWriter(GURL(), 0));
660 written_response_id_ = writer_->response_id();
661 for (int i = 0; i < kNumBlocks; ++i) {
662 PushNextTaskAsImmediate(
663 base::Bind(&AppCacheResponseTest::WriteOneBlock,
664 base::Unretained(this), kNumBlocks - i));
666 ScheduleNextTask();
669 void ReadInBlocksImmediately() {
670 writer_.reset();
671 reader_.reset(service_->storage()->CreateResponseReader(
672 GURL(), 0, written_response_id_));
673 for (int i = 0; i < kNumBlocks; ++i) {
674 PushNextTaskAsImmediate(
675 base::Bind(&AppCacheResponseTest::ReadOneBlockImmediately,
676 base::Unretained(this),
677 kNumBlocks - i));
679 ScheduleNextTask();
682 void ReadOneBlockImmediately(int block_number) {
683 PushNextTaskAsImmediate(base::Bind(&AppCacheResponseTest::VerifyOneBlock,
684 base::Unretained(this), block_number));
685 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
688 // DeleteWithinCallbacks -------------------------------------------
689 void DeleteWithinCallbacks() {
690 // 1. Write out a few blocks normally, and upon
691 // completion of the last write, delete the writer.
692 // 2. Read in a few blocks normally, and upon completion
693 // of the last read, delete the reader.
695 should_delete_reader_in_completion_callback_ = true;
696 reader_deletion_count_down_ = kNumBlocks;
697 should_delete_writer_in_completion_callback_ = true;
698 writer_deletion_count_down_ = kNumBlocks;
700 PushNextTask(base::Bind(&AppCacheResponseTest::ReadInBlocks,
701 base::Unretained(this)));
702 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks,
703 base::Unretained(this)));
704 ScheduleNextTask();
707 // DeleteWithIOPending -------------------------------------------
708 void DeleteWithIOPending() {
709 // 1. Write a few blocks normally.
710 // 2. Start a write, delete with it pending.
711 // 3. Start a read, delete with it pending.
712 PushNextTask(base::Bind(&AppCacheResponseTest::ReadThenDelete,
713 base::Unretained(this)));
714 PushNextTask(base::Bind(&AppCacheResponseTest::WriteThenDelete,
715 base::Unretained(this)));
716 PushNextTask(base::Bind(&AppCacheResponseTest::WriteOutBlocks,
717 base::Unretained(this)));
718 ScheduleNextTask();
721 void WriteThenDelete() {
722 write_callback_was_called_ = false;
723 WriteOneBlock(5);
724 EXPECT_TRUE(writer_->IsWritePending());
725 writer_.reset();
726 ScheduleNextTask();
729 void ReadThenDelete() {
730 read_callback_was_called_ = false;
731 reader_.reset(service_->storage()->CreateResponseReader(
732 GURL(), 0, written_response_id_));
733 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
734 EXPECT_TRUE(reader_->IsReadPending());
735 reader_.reset();
737 // Wait a moment to verify no callbacks.
738 base::MessageLoop::current()->PostDelayedTask(
739 FROM_HERE, base::Bind(&AppCacheResponseTest::VerifyNoCallbacks,
740 base::Unretained(this)),
741 base::TimeDelta::FromMilliseconds(10));
744 void VerifyNoCallbacks() {
745 EXPECT_TRUE(!write_callback_was_called_);
746 EXPECT_TRUE(!read_callback_was_called_);
747 TestFinished();
750 // Data members
752 scoped_ptr<base::WaitableEvent> test_finished_event_;
753 scoped_ptr<MockStorageDelegate> storage_delegate_;
754 scoped_ptr<MockAppCacheService> service_;
755 std::stack<std::pair<base::Closure, bool> > task_stack_;
757 scoped_ptr<AppCacheResponseReader> reader_;
758 scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_;
759 scoped_refptr<IOBuffer> read_buffer_;
760 int expected_read_result_;
761 bool should_delete_reader_in_completion_callback_;
762 int reader_deletion_count_down_;
763 bool read_callback_was_called_;
765 int64 written_response_id_;
766 scoped_ptr<AppCacheResponseWriter> writer_;
767 scoped_ptr<AppCacheResponseMetadataWriter> metadata_writer_;
768 scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
769 scoped_refptr<IOBuffer> write_buffer_;
770 int expected_write_result_;
771 bool should_delete_writer_in_completion_callback_;
772 int writer_deletion_count_down_;
773 bool write_callback_was_called_;
775 static scoped_ptr<base::Thread> io_thread_;
778 // static
779 scoped_ptr<base::Thread> AppCacheResponseTest::io_thread_;
781 TEST_F(AppCacheResponseTest, ReadNonExistentResponse) {
782 RunTestOnIOThread(&AppCacheResponseTest::ReadNonExistentResponse);
785 TEST_F(AppCacheResponseTest, LoadResponseInfo_Miss) {
786 RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Miss);
789 TEST_F(AppCacheResponseTest, LoadResponseInfo_Hit) {
790 RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Hit);
793 TEST_F(AppCacheResponseTest, Metadata) {
794 RunTestOnIOThread(&AppCacheResponseTest::Metadata);
797 TEST_F(AppCacheResponseTest, AmountWritten) {
798 RunTestOnIOThread(&AppCacheResponseTest::AmountWritten);
801 TEST_F(AppCacheResponseTest, WriteThenVariouslyReadResponse) {
802 RunTestOnIOThread(&AppCacheResponseTest::WriteThenVariouslyReadResponse);
805 TEST_F(AppCacheResponseTest, IOChaining) {
806 RunTestOnIOThread(&AppCacheResponseTest::IOChaining);
809 TEST_F(AppCacheResponseTest, DeleteWithinCallbacks) {
810 RunTestOnIOThread(&AppCacheResponseTest::DeleteWithinCallbacks);
813 TEST_F(AppCacheResponseTest, DeleteWithIOPending) {
814 RunTestOnIOThread(&AppCacheResponseTest::DeleteWithIOPending);
817 } // namespace content