blob: 29895929f16dbf1f533eb32e2d8734230b0ea38b [file] [log] [blame]
[email protected]3f2b9092009-12-29 00:59:311// Copyright (c) 2009 The Chromium Authors. All rights reserved.
[email protected]073aabe2009-10-21 18:09:332// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/compiler_specific.h"
6#include "base/pickle.h"
7#include "base/thread.h"
8#include "base/waitable_event.h"
9#include "net/base/io_buffer.h"
10#include "testing/gtest/include/gtest/gtest.h"
11#include "webkit/appcache/appcache_response.h"
12#include "webkit/appcache/mock_appcache_service.h"
13
14using net::IOBuffer;
[email protected]3367fc1d2009-11-09 00:09:2115using net::WrappedIOBuffer;
[email protected]073aabe2009-10-21 18:09:3316
17namespace appcache {
18
[email protected]dda06f82009-10-21 18:38:5119static const int kNumBlocks = 4;
20static const int kBlockSize = 1024;
21static const int kNoSuchResponseId = 123;
22
[email protected]073aabe2009-10-21 18:09:3323class AppCacheResponseTest : public testing::Test {
24 public:
25
26 // Test Harness -------------------------------------------------------------
27
28 // Helper class used to verify test results
29 class MockStorageDelegate : public AppCacheStorage::Delegate {
30 public:
31 explicit MockStorageDelegate(AppCacheResponseTest* test)
32 : loaded_info_id_(0), test_(test) {
33 }
34
35 virtual void OnResponseInfoLoaded(AppCacheResponseInfo* info,
36 int64 response_id) {
37 loaded_info_ = info;
38 loaded_info_id_ = response_id;
39 test_->ScheduleNextTask();
40 }
41
42 scoped_refptr<AppCacheResponseInfo> loaded_info_;
43 int64 loaded_info_id_;
44 AppCacheResponseTest* test_;
45 };
46
47 // Helper class run a test on our io_thread. The io_thread
48 // is spun up once and reused for all tests.
49 template <class Method>
50 class WrapperTask : public Task {
51 public:
52 WrapperTask(AppCacheResponseTest* test, Method method)
53 : test_(test), method_(method) {
54 }
55
56 virtual void Run() {
57 test_->SetUpTest();
58 (test_->*method_)();
59 }
60
61 private:
62 AppCacheResponseTest* test_;
63 Method method_;
64 };
65
66 static void SetUpTestCase() {
67 io_thread_.reset(new base::Thread("AppCacheResponseTest Thread"));
68 base::Thread::Options options(MessageLoop::TYPE_IO, 0);
69 io_thread_->StartWithOptions(options);
70 }
71
72 static void TearDownTestCase() {
73 io_thread_.reset(NULL);
74 }
75
76 AppCacheResponseTest()
77 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
78 ALLOW_THIS_IN_INITIALIZER_LIST(read_callback_(
79 this, &AppCacheResponseTest::OnReadComplete)),
80 ALLOW_THIS_IN_INITIALIZER_LIST(read_info_callback_(
81 this, &AppCacheResponseTest::OnReadInfoComplete)),
82 ALLOW_THIS_IN_INITIALIZER_LIST(write_callback_(
83 this, &AppCacheResponseTest::OnWriteComplete)),
84 ALLOW_THIS_IN_INITIALIZER_LIST(write_info_callback_(
85 this, &AppCacheResponseTest::OnWriteInfoComplete)) {
86 }
87
88 template <class Method>
89 void RunTestOnIOThread(Method method) {
90 test_finished_event_ .reset(new base::WaitableEvent(false, false));
91 io_thread_->message_loop()->PostTask(
92 FROM_HERE, new WrapperTask<Method>(this, method));
93 test_finished_event_->Wait();
94 }
95
96 void SetUpTest() {
97 DCHECK(MessageLoop::current() == io_thread_->message_loop());
98 DCHECK(task_stack_.empty());
99 storage_delegate_.reset(new MockStorageDelegate(this));
100 service_.reset(new MockAppCacheService());
101 expected_read_result_ = 0;
102 expected_write_result_ = 0;
103 written_response_id_ = 0;
104 should_delete_reader_in_completion_callback_ = false;
105 should_delete_writer_in_completion_callback_ = false;
106 reader_deletion_count_down_ = 0;
107 writer_deletion_count_down_ = 0;
108 read_callback_was_called_ = false;
109 write_callback_was_called_ = false;
110 }
111
112 void TearDownTest() {
113 DCHECK(MessageLoop::current() == io_thread_->message_loop());
114 while (!task_stack_.empty()) {
115 delete task_stack_.top().first;
116 task_stack_.pop();
117 }
118 reader_.reset();
119 read_buffer_ = NULL;
120 read_info_buffer_ = NULL;
121 writer_.reset();
122 write_buffer_ = NULL;
123 write_info_buffer_ = NULL;
124 storage_delegate_.reset();
125 service_.reset();
126 }
127
128 void TestFinished() {
129 // We unwind the stack prior to finishing up to let stack
130 // based objects get deleted.
131 DCHECK(MessageLoop::current() == io_thread_->message_loop());
132 MessageLoop::current()->PostTask(FROM_HERE,
133 method_factory_.NewRunnableMethod(
134 &AppCacheResponseTest::TestFinishedUnwound));
135 }
136
137 void TestFinishedUnwound() {
138 TearDownTest();
139 test_finished_event_->Signal();
140 }
141
142 void PushNextTask(Task* task) {
143 task_stack_.push(std::pair<Task*, bool>(task, false));
144 }
145
146 void PushNextTaskAsImmediate(Task* task) {
147 task_stack_.push(std::pair<Task*, bool>(task, true));
148 }
149
150 void ScheduleNextTask() {
151 DCHECK(MessageLoop::current() == io_thread_->message_loop());
152 if (task_stack_.empty()) {
153 TestFinished();
154 return;
155 }
156 scoped_ptr<Task> task(task_stack_.top().first);
157 bool immediate = task_stack_.top().second;
158 task_stack_.pop();
159 if (immediate)
160 task->Run();
161 else
162 MessageLoop::current()->PostTask(FROM_HERE, task.release());
163 }
164
165 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
166
167 void WriteBasicResponse() {
[email protected]3367fc1d2009-11-09 00:09:21168 static const char kHttpHeaders[] =
169 "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
170 static const char* kHttpBody = "Hello";
171 scoped_refptr<IOBuffer> body = new WrappedIOBuffer(kHttpBody);
172 std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
173 WriteResponse(MakeHttpResponseInfo(raw_headers), body, strlen(kHttpBody));
[email protected]073aabe2009-10-21 18:09:33174 }
175
[email protected]3367fc1d2009-11-09 00:09:21176 void WriteResponse(net::HttpResponseInfo* head,
177 IOBuffer* body, int body_len) {
178 DCHECK(body);
179 scoped_refptr<IOBuffer> body_ref(body);
[email protected]073aabe2009-10-21 18:09:33180 PushNextTask(method_factory_.NewRunnableMethod(
181 &AppCacheResponseTest::WriteResponseBody,
[email protected]3367fc1d2009-11-09 00:09:21182 body_ref, body_len));
[email protected]073aabe2009-10-21 18:09:33183 WriteResponseHead(head);
184 }
185
186 void WriteResponseHead(net::HttpResponseInfo* head) {
187 EXPECT_FALSE(writer_->IsWritePending());
188 expected_write_result_ = GetHttpResponseInfoSize(head);
189 write_info_buffer_ = new HttpResponseInfoIOBuffer(head);
190 writer_->WriteInfo(write_info_buffer_, &write_info_callback_);
191 }
192
193 void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
194 EXPECT_FALSE(writer_->IsWritePending());
195 write_buffer_ = io_buffer;
196 expected_write_result_ = buf_len;
197 writer_->WriteData(
198 write_buffer_, buf_len, &write_callback_);
199 }
200
201 void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
202 EXPECT_FALSE(reader_->IsReadPending());
203 read_buffer_ = io_buffer;
204 expected_read_result_ = buf_len;
205 reader_->ReadData(
206 read_buffer_, buf_len, &read_callback_);
207 }
208
209 // AppCacheResponseReader / Writer completion callbacks
210
211 void OnWriteInfoComplete(int result) {
212 EXPECT_FALSE(writer_->IsWritePending());
213 EXPECT_EQ(expected_write_result_, result);
214 ScheduleNextTask();
215 }
216
217 void OnWriteComplete(int result) {
218 EXPECT_FALSE(writer_->IsWritePending());
219 write_callback_was_called_ = true;
220 EXPECT_EQ(expected_write_result_, result);
221 if (should_delete_writer_in_completion_callback_ &&
222 --writer_deletion_count_down_ == 0) {
223 writer_.reset();
224 }
225 ScheduleNextTask();
226 }
227
228 void OnReadInfoComplete(int result) {
229 EXPECT_FALSE(reader_->IsReadPending());
230 EXPECT_EQ(expected_read_result_, result);
231 ScheduleNextTask();
232 }
233
234 void OnReadComplete(int result) {
235 EXPECT_FALSE(reader_->IsReadPending());
236 read_callback_was_called_ = true;
237 EXPECT_EQ(expected_read_result_, result);
238 if (should_delete_reader_in_completion_callback_ &&
239 --reader_deletion_count_down_ == 0) {
240 reader_.reset();
241 }
242 ScheduleNextTask();
243 }
244
245 // Helpers to work with HttpResponseInfo objects
246
[email protected]3367fc1d2009-11-09 00:09:21247 net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
[email protected]073aabe2009-10-21 18:09:33248 net::HttpResponseInfo* info = new net::HttpResponseInfo;
249 info->request_time = base::Time::Now();
250 info->response_time = base::Time::Now();
251 info->was_cached = false;
252 info->headers = new net::HttpResponseHeaders(raw_headers);
253 return info;
254 }
255
256 int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
257 Pickle pickle;
258 return PickleHttpResonseInfo(&pickle, info);
259 }
260
261 bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
262 const net::HttpResponseInfo* info2) {
263 Pickle pickle1;
264 Pickle pickle2;
265 PickleHttpResonseInfo(&pickle1, info1);
266 PickleHttpResonseInfo(&pickle2, info2);
267 return (pickle1.size() == pickle2.size()) &&
268 (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
269 }
270
271 int PickleHttpResonseInfo(Pickle* pickle, const net::HttpResponseInfo* info) {
272 const bool kSkipTransientHeaders = true;
273 const bool kTruncated = false;
274 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
275 return pickle->size();
276 }
277
278 // Helpers to fill and verify blocks of memory with a value
279
280 void FillData(char value, char* data, int data_len) {
281 memset(data, value, data_len);
282 }
283
284 bool CheckData(char value, const char* data, int data_len) {
285 for (int i = 0; i < data_len; ++i, ++data) {
286 if (*data != value)
287 return false;
288 }
289 return true;
290 }
291
292 // Individual Tests ---------------------------------------------------------
293 // Most of the individual tests involve multiple async steps. Each test
294 // is delineated with a section header.
295
[email protected]073aabe2009-10-21 18:09:33296
297 // ReadNonExistentResponse -------------------------------------------
[email protected]073aabe2009-10-21 18:09:33298 void ReadNonExistentResponse() {
299 // 1. Attempt to ReadInfo
300 // 2. Attempt to ReadData
301
302 reader_.reset(service_->storage()->CreateResponseReader(
[email protected]dda06f82009-10-21 18:38:51303 GURL(), kNoSuchResponseId));
[email protected]073aabe2009-10-21 18:09:33304
305 // Push tasks in reverse order
306 PushNextTask(method_factory_.NewRunnableMethod(
307 &AppCacheResponseTest::ReadNonExistentData));
308 PushNextTask(method_factory_.NewRunnableMethod(
309 &AppCacheResponseTest::ReadNonExistentInfo));
310 ScheduleNextTask();
311 }
312
313 void ReadNonExistentInfo() {
314 EXPECT_FALSE(reader_->IsReadPending());
315 read_info_buffer_ = new HttpResponseInfoIOBuffer();
316 reader_->ReadInfo(read_info_buffer_, &read_info_callback_);
317 EXPECT_TRUE(reader_->IsReadPending());
318 expected_read_result_ = net::ERR_CACHE_MISS;
319 }
320
321 void ReadNonExistentData() {
322 EXPECT_FALSE(reader_->IsReadPending());
323 read_buffer_ = new IOBuffer(kBlockSize);
324 reader_->ReadData(read_buffer_, kBlockSize, &read_callback_);
325 EXPECT_TRUE(reader_->IsReadPending());
326 expected_read_result_ = net::ERR_CACHE_MISS;
327 }
328
329 // LoadResponseInfo_Miss ----------------------------------------------------
330 void LoadResponseInfo_Miss() {
331 PushNextTask(method_factory_.NewRunnableMethod(
332 &AppCacheResponseTest::LoadResponseInfo_Miss_Verify));
[email protected]dda06f82009-10-21 18:38:51333 service_->storage()->LoadResponseInfo(GURL(), kNoSuchResponseId,
[email protected]073aabe2009-10-21 18:09:33334 storage_delegate_.get());
335 }
336
337 void LoadResponseInfo_Miss_Verify() {
[email protected]dda06f82009-10-21 18:38:51338 EXPECT_EQ(kNoSuchResponseId, storage_delegate_->loaded_info_id_);
[email protected]073aabe2009-10-21 18:09:33339 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(method_factory_.NewRunnableMethod(
351 &AppCacheResponseTest::LoadResponseInfo_Hit_Step2));
352 writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
353 written_response_id_ = writer_->response_id();
354 WriteBasicResponse();
355 }
356
357 void LoadResponseInfo_Hit_Step2() {
358 writer_.reset();
359 PushNextTask(method_factory_.NewRunnableMethod(
360 &AppCacheResponseTest::LoadResponseInfo_Hit_Verify));
361 service_->storage()->LoadResponseInfo(GURL(), 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 TestFinished();
372 }
373
[email protected]0dfeec32010-01-06 22:25:33374 // AmountWritten ----------------------------------------------------
375
376 void AmountWritten() {
377 static const char kHttpHeaders[] =
378 "HTTP/1.0 200 OK\0\0";
379 std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
380 net::HttpResponseInfo* head = MakeHttpResponseInfo(raw_headers);
381 int expected_amount_written =
382 GetHttpResponseInfoSize(head) + kNumBlocks * kBlockSize;
383
384 // Push tasks in reverse order.
385 PushNextTask(method_factory_.NewRunnableMethod(
386 &AppCacheResponseTest::Verify_AmountWritten, expected_amount_written));
387 for (int i = 0; i < kNumBlocks; ++i) {
388 PushNextTask(method_factory_.NewRunnableMethod(
389 &AppCacheResponseTest::WriteOneBlock, kNumBlocks - i));
390 }
391 PushNextTask(method_factory_.NewRunnableMethod(
392 &AppCacheResponseTest::WriteResponseHead, head));
393
394 writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
395 written_response_id_ = writer_->response_id();
396 ScheduleNextTask();
397 }
398
399 void Verify_AmountWritten(int expected_amount_written) {
400 EXPECT_EQ(expected_amount_written, writer_->amount_written());
401 TestFinished();
402 }
403
404
[email protected]073aabe2009-10-21 18:09:33405 // WriteThenVariouslyReadResponse -------------------------------------------
[email protected]073aabe2009-10-21 18:09:33406
407 void WriteThenVariouslyReadResponse() {
408 // This tests involves multiple async steps.
409 // 1. First, write a large body using multiple writes, we don't bother
410 // with a response head for this test.
411 // 2. Read the entire body, using multiple reads
412 // 3. Read the entire body, using one read.
413 // 4. Attempt to read beyond the EOF.
414 // 5. Read just a range.
415 // 6. Attempt to read beyond EOF of a range.
416
417 // Push tasks in reverse order
418 PushNextTask(method_factory_.NewRunnableMethod(
419 &AppCacheResponseTest::ReadRangeFullyBeyondEOF));
420 PushNextTask(method_factory_.NewRunnableMethod(
421 &AppCacheResponseTest::ReadRangePartiallyBeyondEOF));
422 PushNextTask(method_factory_.NewRunnableMethod(
423 &AppCacheResponseTest::ReadPastEOF));
424 PushNextTask(method_factory_.NewRunnableMethod(
425 &AppCacheResponseTest::ReadRange));
426 PushNextTask(method_factory_.NewRunnableMethod(
427 &AppCacheResponseTest::ReadPastEOF));
428 PushNextTask(method_factory_.NewRunnableMethod(
429 &AppCacheResponseTest::ReadAllAtOnce));
430 PushNextTask(method_factory_.NewRunnableMethod(
431 &AppCacheResponseTest::ReadInBlocks));
432 PushNextTask(method_factory_.NewRunnableMethod(
433 &AppCacheResponseTest::WriteOutBlocks));
434
435 // Get them going.
436 ScheduleNextTask();
437 }
438
439 void WriteOutBlocks() {
440 writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
441 written_response_id_ = writer_->response_id();
442 for (int i = 0; i < kNumBlocks; ++i) {
443 PushNextTask(method_factory_.NewRunnableMethod(
444 &AppCacheResponseTest::WriteOneBlock, kNumBlocks - i));
445 }
446 ScheduleNextTask();
447 }
448
449 void WriteOneBlock(int block_number) {
450 scoped_refptr<IOBuffer> io_buffer =
451 new IOBuffer(kBlockSize);
452 FillData(block_number, io_buffer->data(), kBlockSize);
453 WriteResponseBody(io_buffer, kBlockSize);
454 }
455
456 void ReadInBlocks() {
457 writer_.reset();
458 reader_.reset(service_->storage()->CreateResponseReader(
459 GURL(), written_response_id_));
460 for (int i = 0; i < kNumBlocks; ++i) {
461 PushNextTask(method_factory_.NewRunnableMethod(
462 &AppCacheResponseTest::ReadOneBlock, kNumBlocks - i));
463 }
464 ScheduleNextTask();
465 }
466
467 void ReadOneBlock(int block_number) {
468 PushNextTask(method_factory_.NewRunnableMethod(
469 &AppCacheResponseTest::VerifyOneBlock, block_number));
470 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
471 }
472
473 void VerifyOneBlock(int block_number) {
474 EXPECT_TRUE(CheckData(block_number, read_buffer_->data(), kBlockSize));
475 ScheduleNextTask();
476 }
477
478 void ReadAllAtOnce() {
479 PushNextTask(method_factory_.NewRunnableMethod(
480 &AppCacheResponseTest::VerifyAllAtOnce));
481 reader_.reset(service_->storage()->CreateResponseReader(
482 GURL(), written_response_id_));
483 int big_size = kNumBlocks * kBlockSize;
484 ReadResponseBody(new IOBuffer(big_size), big_size);
485 }
486
487 void VerifyAllAtOnce() {
488 char* p = read_buffer_->data();
489 for (int i = 0; i < kNumBlocks; ++i, p += kBlockSize)
490 EXPECT_TRUE(CheckData(i + 1, p, kBlockSize));
491 ScheduleNextTask();
492 }
493
494 void ReadPastEOF() {
495 EXPECT_FALSE(reader_->IsReadPending());
496 read_buffer_ = new IOBuffer(kBlockSize);
497 expected_read_result_ = 0;
498 reader_->ReadData(
499 read_buffer_, kBlockSize, &read_callback_);
500 }
501
502 void ReadRange() {
503 PushNextTask(method_factory_.NewRunnableMethod(
504 &AppCacheResponseTest::VerifyRange));
505 reader_.reset(service_->storage()->CreateResponseReader(
506 GURL(), written_response_id_));
507 reader_->SetReadRange(kBlockSize, kBlockSize);
508 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
509 }
510
511 void VerifyRange() {
512 EXPECT_TRUE(CheckData(2, read_buffer_->data(), kBlockSize));
513 ScheduleNextTask(); // ReadPastEOF is scheduled next
514 }
515
516 void ReadRangePartiallyBeyondEOF() {
517 PushNextTask(method_factory_.NewRunnableMethod(
518 &AppCacheResponseTest::VerifyRangeBeyondEOF));
519 reader_.reset(service_->storage()->CreateResponseReader(
520 GURL(), written_response_id_));
521 reader_->SetReadRange(kBlockSize, kNumBlocks * kBlockSize);
522 ReadResponseBody(new IOBuffer(kNumBlocks * kBlockSize),
523 kNumBlocks * kBlockSize);
524 expected_read_result_ = (kNumBlocks - 1) * kBlockSize;
525 }
526
527 void VerifyRangeBeyondEOF() {
528 // Just verify the first 1k
529 VerifyRange();
530 }
531
532 void ReadRangeFullyBeyondEOF() {
533 reader_.reset(service_->storage()->CreateResponseReader(
534 GURL(), written_response_id_));
535 reader_->SetReadRange((kNumBlocks * kBlockSize) + 1, kBlockSize);
536 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
537 expected_read_result_ = 0;
538 }
539
540 // IOChaining -------------------------------------------
541 void IOChaining() {
542 // 1. Write several blocks out initiating the subsequent write
543 // from within the completion callback of the previous write.
544 // 2. Read and verify several blocks in similarly chaining reads.
545
546 // Push tasks in reverse order
547 PushNextTaskAsImmediate(method_factory_.NewRunnableMethod(
548 &AppCacheResponseTest::ReadInBlocksImmediately));
549 PushNextTaskAsImmediate(method_factory_.NewRunnableMethod(
550 &AppCacheResponseTest::WriteOutBlocksImmediately));
551
552 // Get them going.
553 ScheduleNextTask();
554 }
555
556 void WriteOutBlocksImmediately() {
557 writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
558 written_response_id_ = writer_->response_id();
559 for (int i = 0; i < kNumBlocks; ++i) {
560 PushNextTaskAsImmediate(method_factory_.NewRunnableMethod(
561 &AppCacheResponseTest::WriteOneBlock, kNumBlocks - i));
562 }
563 ScheduleNextTask();
564 }
565
566 void ReadInBlocksImmediately() {
567 writer_.reset();
568 reader_.reset(service_->storage()->CreateResponseReader(
569 GURL(), written_response_id_));
570 for (int i = 0; i < kNumBlocks; ++i) {
571 PushNextTaskAsImmediate(method_factory_.NewRunnableMethod(
572 &AppCacheResponseTest::ReadOneBlockImmediately, kNumBlocks - i));
573 }
574 ScheduleNextTask();
575 }
576
577 void ReadOneBlockImmediately(int block_number) {
578 PushNextTaskAsImmediate(method_factory_.NewRunnableMethod(
579 &AppCacheResponseTest::VerifyOneBlock, block_number));
580 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
581 }
582
583 // DeleteWithinCallbacks -------------------------------------------
584 void DeleteWithinCallbacks() {
585 // 1. Write out a few blocks normally, and upon
586 // completion of the last write, delete the writer.
587 // 2. Read in a few blocks normally, and upon completion
588 // of the last read, delete the reader.
589
590 should_delete_reader_in_completion_callback_ = true;
591 reader_deletion_count_down_ = kNumBlocks;
592 should_delete_writer_in_completion_callback_ = true;
593 writer_deletion_count_down_ = kNumBlocks;
594
595 PushNextTask(method_factory_.NewRunnableMethod(
596 &AppCacheResponseTest::ReadInBlocks));
597 PushNextTask(method_factory_.NewRunnableMethod(
598 &AppCacheResponseTest::WriteOutBlocks));
599 ScheduleNextTask();
600 }
601
602 // DeleteWithIOPending -------------------------------------------
603 void DeleteWithIOPending() {
604 // 1. Write a few blocks normally.
605 // 2. Start a write, delete with it pending.
606 // 3. Start a read, delete with it pending.
607 PushNextTask(method_factory_.NewRunnableMethod(
608 &AppCacheResponseTest::ReadThenDelete));
609 PushNextTask(method_factory_.NewRunnableMethod(
610 &AppCacheResponseTest::WriteThenDelete));
611 PushNextTask(method_factory_.NewRunnableMethod(
612 &AppCacheResponseTest::WriteOutBlocks));
613 ScheduleNextTask();
614 }
615
616 void WriteThenDelete() {
617 write_callback_was_called_ = false;
618 WriteOneBlock(5);
619 EXPECT_TRUE(writer_->IsWritePending());
620 writer_.reset();
621 ScheduleNextTask();
622 }
623
624 void ReadThenDelete() {
625 read_callback_was_called_ = false;
626 reader_.reset(service_->storage()->CreateResponseReader(
627 GURL(), written_response_id_));
628 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
629 EXPECT_TRUE(reader_->IsReadPending());
630 reader_.reset();
631
632 // Wait a moment to verify no callbacks.
633 MessageLoop::current()->PostDelayedTask(FROM_HERE,
634 method_factory_.NewRunnableMethod(
635 &AppCacheResponseTest::VerifyNoCallbacks),
636 10);
637 }
638
639 void VerifyNoCallbacks() {
640 EXPECT_TRUE(!write_callback_was_called_);
641 EXPECT_TRUE(!read_callback_was_called_);
642 TestFinished();
643 }
644
645 // Data members
646
647 ScopedRunnableMethodFactory<AppCacheResponseTest> method_factory_;
648 scoped_ptr<base::WaitableEvent> test_finished_event_;
649 scoped_ptr<MockStorageDelegate> storage_delegate_;
650 scoped_ptr<MockAppCacheService> service_;
651 std::stack<std::pair<Task*, bool> > task_stack_;
652
653 scoped_ptr<AppCacheResponseReader> reader_;
654 scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_;
655 scoped_refptr<IOBuffer> read_buffer_;
656 int expected_read_result_;
657 net::CompletionCallbackImpl<AppCacheResponseTest> read_callback_;
658 net::CompletionCallbackImpl<AppCacheResponseTest> read_info_callback_;
659 bool should_delete_reader_in_completion_callback_;
660 int reader_deletion_count_down_;
661 bool read_callback_was_called_;
662
663 int64 written_response_id_;
664 scoped_ptr<AppCacheResponseWriter> writer_;
665 scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
666 scoped_refptr<IOBuffer> write_buffer_;
667 int expected_write_result_;
668 net::CompletionCallbackImpl<AppCacheResponseTest> write_callback_;
669 net::CompletionCallbackImpl<AppCacheResponseTest> write_info_callback_;
670 bool should_delete_writer_in_completion_callback_;
671 int writer_deletion_count_down_;
672 bool write_callback_was_called_;
673
674 static scoped_ptr<base::Thread> io_thread_;
675};
676
677// static
678scoped_ptr<base::Thread> AppCacheResponseTest::io_thread_;
679
[email protected]073aabe2009-10-21 18:09:33680TEST_F(AppCacheResponseTest, ReadNonExistentResponse) {
681 RunTestOnIOThread(&AppCacheResponseTest::ReadNonExistentResponse);
682}
683
684TEST_F(AppCacheResponseTest, LoadResponseInfo_Miss) {
685 RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Miss);
686}
687
688TEST_F(AppCacheResponseTest, LoadResponseInfo_Hit) {
689 RunTestOnIOThread(&AppCacheResponseTest::LoadResponseInfo_Hit);
690}
691
[email protected]0dfeec32010-01-06 22:25:33692TEST_F(AppCacheResponseTest, AmountWritten) {
693 RunTestOnIOThread(&AppCacheResponseTest::AmountWritten);
694}
695
[email protected]073aabe2009-10-21 18:09:33696TEST_F(AppCacheResponseTest, WriteThenVariouslyReadResponse) {
697 RunTestOnIOThread(&AppCacheResponseTest::WriteThenVariouslyReadResponse);
698}
699
700TEST_F(AppCacheResponseTest, IOChaining) {
701 RunTestOnIOThread(&AppCacheResponseTest::IOChaining);
702}
703
704TEST_F(AppCacheResponseTest, DeleteWithinCallbacks) {
705 RunTestOnIOThread(&AppCacheResponseTest::DeleteWithinCallbacks);
706}
707
708TEST_F(AppCacheResponseTest, DeleteWithIOPending) {
709 RunTestOnIOThread(&AppCacheResponseTest::DeleteWithIOPending);
710}
711
712} // namespace appcache
713