blob: c0a4eb5855d634d4b284e6ca5194a84efa433385 [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"
[email protected]80d42812010-02-09 10:30:2510#include "net/base/net_errors.h"
[email protected]073aabe2009-10-21 18:09:3311#include "testing/gtest/include/gtest/gtest.h"
12#include "webkit/appcache/appcache_response.h"
13#include "webkit/appcache/mock_appcache_service.h"
14
15using net::IOBuffer;
[email protected]3367fc1d2009-11-09 00:09:2116using net::WrappedIOBuffer;
[email protected]073aabe2009-10-21 18:09:3317
18namespace appcache {
19
[email protected]dda06f82009-10-21 18:38:5120static const int kNumBlocks = 4;
21static const int kBlockSize = 1024;
22static const int kNoSuchResponseId = 123;
23
[email protected]073aabe2009-10-21 18:09:3324class AppCacheResponseTest : public testing::Test {
25 public:
26
27 // Test Harness -------------------------------------------------------------
28
29 // Helper class used to verify test results
30 class MockStorageDelegate : public AppCacheStorage::Delegate {
31 public:
32 explicit MockStorageDelegate(AppCacheResponseTest* test)
33 : loaded_info_id_(0), test_(test) {
34 }
35
36 virtual void OnResponseInfoLoaded(AppCacheResponseInfo* info,
37 int64 response_id) {
38 loaded_info_ = info;
39 loaded_info_id_ = response_id;
40 test_->ScheduleNextTask();
41 }
42
43 scoped_refptr<AppCacheResponseInfo> loaded_info_;
44 int64 loaded_info_id_;
45 AppCacheResponseTest* test_;
46 };
47
48 // Helper class run a test on our io_thread. The io_thread
49 // is spun up once and reused for all tests.
50 template <class Method>
51 class WrapperTask : public Task {
52 public:
53 WrapperTask(AppCacheResponseTest* test, Method method)
54 : test_(test), method_(method) {
55 }
56
57 virtual void Run() {
58 test_->SetUpTest();
59 (test_->*method_)();
60 }
61
62 private:
63 AppCacheResponseTest* test_;
64 Method method_;
65 };
66
67 static void SetUpTestCase() {
68 io_thread_.reset(new base::Thread("AppCacheResponseTest Thread"));
69 base::Thread::Options options(MessageLoop::TYPE_IO, 0);
70 io_thread_->StartWithOptions(options);
71 }
72
73 static void TearDownTestCase() {
74 io_thread_.reset(NULL);
75 }
76
77 AppCacheResponseTest()
[email protected]79b15b22010-05-19 00:38:5678 : ALLOW_THIS_IN_INITIALIZER_LIST(read_callback_(
[email protected]073aabe2009-10-21 18:09:3379 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,
[email protected]79b15b22010-05-19 00:38:56133 NewRunnableMethod(this, &AppCacheResponseTest::TestFinishedUnwound));
[email protected]073aabe2009-10-21 18:09:33134 }
135
136 void TestFinishedUnwound() {
137 TearDownTest();
138 test_finished_event_->Signal();
139 }
140
141 void PushNextTask(Task* task) {
142 task_stack_.push(std::pair<Task*, bool>(task, false));
143 }
144
145 void PushNextTaskAsImmediate(Task* task) {
146 task_stack_.push(std::pair<Task*, bool>(task, true));
147 }
148
149 void ScheduleNextTask() {
150 DCHECK(MessageLoop::current() == io_thread_->message_loop());
151 if (task_stack_.empty()) {
152 TestFinished();
153 return;
154 }
155 scoped_ptr<Task> task(task_stack_.top().first);
156 bool immediate = task_stack_.top().second;
157 task_stack_.pop();
158 if (immediate)
159 task->Run();
160 else
161 MessageLoop::current()->PostTask(FROM_HERE, task.release());
162 }
163
164 // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
165
166 void WriteBasicResponse() {
[email protected]3367fc1d2009-11-09 00:09:21167 static const char kHttpHeaders[] =
168 "HTTP/1.0 200 OK\0Content-Length: 5\0\0";
169 static const char* kHttpBody = "Hello";
170 scoped_refptr<IOBuffer> body = new WrappedIOBuffer(kHttpBody);
171 std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
172 WriteResponse(MakeHttpResponseInfo(raw_headers), body, strlen(kHttpBody));
[email protected]073aabe2009-10-21 18:09:33173 }
174
[email protected]fd2885a2010-03-17 22:02:28175 int basic_response_size() { return 5; } // should match kHttpBody above
176
[email protected]3367fc1d2009-11-09 00:09:21177 void WriteResponse(net::HttpResponseInfo* head,
178 IOBuffer* body, int body_len) {
179 DCHECK(body);
180 scoped_refptr<IOBuffer> body_ref(body);
[email protected]79b15b22010-05-19 00:38:56181 PushNextTask(NewRunnableMethod(
182 this, &AppCacheResponseTest::WriteResponseBody,
[email protected]3367fc1d2009-11-09 00:09:21183 body_ref, body_len));
[email protected]073aabe2009-10-21 18:09:33184 WriteResponseHead(head);
185 }
186
187 void WriteResponseHead(net::HttpResponseInfo* head) {
188 EXPECT_FALSE(writer_->IsWritePending());
189 expected_write_result_ = GetHttpResponseInfoSize(head);
190 write_info_buffer_ = new HttpResponseInfoIOBuffer(head);
191 writer_->WriteInfo(write_info_buffer_, &write_info_callback_);
192 }
193
194 void WriteResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
195 EXPECT_FALSE(writer_->IsWritePending());
196 write_buffer_ = io_buffer;
197 expected_write_result_ = buf_len;
198 writer_->WriteData(
199 write_buffer_, buf_len, &write_callback_);
200 }
201
202 void ReadResponseBody(scoped_refptr<IOBuffer> io_buffer, int buf_len) {
203 EXPECT_FALSE(reader_->IsReadPending());
204 read_buffer_ = io_buffer;
205 expected_read_result_ = buf_len;
206 reader_->ReadData(
207 read_buffer_, buf_len, &read_callback_);
208 }
209
210 // AppCacheResponseReader / Writer completion callbacks
211
212 void OnWriteInfoComplete(int result) {
213 EXPECT_FALSE(writer_->IsWritePending());
214 EXPECT_EQ(expected_write_result_, result);
215 ScheduleNextTask();
216 }
217
218 void OnWriteComplete(int result) {
219 EXPECT_FALSE(writer_->IsWritePending());
220 write_callback_was_called_ = true;
221 EXPECT_EQ(expected_write_result_, result);
222 if (should_delete_writer_in_completion_callback_ &&
223 --writer_deletion_count_down_ == 0) {
224 writer_.reset();
225 }
226 ScheduleNextTask();
227 }
228
229 void OnReadInfoComplete(int result) {
230 EXPECT_FALSE(reader_->IsReadPending());
231 EXPECT_EQ(expected_read_result_, result);
232 ScheduleNextTask();
233 }
234
235 void OnReadComplete(int result) {
236 EXPECT_FALSE(reader_->IsReadPending());
237 read_callback_was_called_ = true;
238 EXPECT_EQ(expected_read_result_, result);
239 if (should_delete_reader_in_completion_callback_ &&
240 --reader_deletion_count_down_ == 0) {
241 reader_.reset();
242 }
243 ScheduleNextTask();
244 }
245
246 // Helpers to work with HttpResponseInfo objects
247
[email protected]3367fc1d2009-11-09 00:09:21248 net::HttpResponseInfo* MakeHttpResponseInfo(const std::string& raw_headers) {
[email protected]073aabe2009-10-21 18:09:33249 net::HttpResponseInfo* info = new net::HttpResponseInfo;
250 info->request_time = base::Time::Now();
251 info->response_time = base::Time::Now();
252 info->was_cached = false;
253 info->headers = new net::HttpResponseHeaders(raw_headers);
254 return info;
255 }
256
257 int GetHttpResponseInfoSize(const net::HttpResponseInfo* info) {
258 Pickle pickle;
259 return PickleHttpResonseInfo(&pickle, info);
260 }
261
262 bool CompareHttpResponseInfos(const net::HttpResponseInfo* info1,
263 const net::HttpResponseInfo* info2) {
264 Pickle pickle1;
265 Pickle pickle2;
266 PickleHttpResonseInfo(&pickle1, info1);
267 PickleHttpResonseInfo(&pickle2, info2);
268 return (pickle1.size() == pickle2.size()) &&
269 (0 == memcmp(pickle1.data(), pickle2.data(), pickle1.size()));
270 }
271
272 int PickleHttpResonseInfo(Pickle* pickle, const net::HttpResponseInfo* info) {
273 const bool kSkipTransientHeaders = true;
274 const bool kTruncated = false;
275 info->Persist(pickle, kSkipTransientHeaders, kTruncated);
276 return pickle->size();
277 }
278
279 // Helpers to fill and verify blocks of memory with a value
280
281 void FillData(char value, char* data, int data_len) {
282 memset(data, value, data_len);
283 }
284
285 bool CheckData(char value, const char* data, int data_len) {
286 for (int i = 0; i < data_len; ++i, ++data) {
287 if (*data != value)
288 return false;
289 }
290 return true;
291 }
292
293 // Individual Tests ---------------------------------------------------------
294 // Most of the individual tests involve multiple async steps. Each test
295 // is delineated with a section header.
296
[email protected]073aabe2009-10-21 18:09:33297
298 // ReadNonExistentResponse -------------------------------------------
[email protected]073aabe2009-10-21 18:09:33299 void ReadNonExistentResponse() {
300 // 1. Attempt to ReadInfo
301 // 2. Attempt to ReadData
302
303 reader_.reset(service_->storage()->CreateResponseReader(
[email protected]dda06f82009-10-21 18:38:51304 GURL(), kNoSuchResponseId));
[email protected]073aabe2009-10-21 18:09:33305
306 // Push tasks in reverse order
[email protected]79b15b22010-05-19 00:38:56307 PushNextTask(NewRunnableMethod(
308 this, &AppCacheResponseTest::ReadNonExistentData));
309 PushNextTask(NewRunnableMethod(
310 this, &AppCacheResponseTest::ReadNonExistentInfo));
[email protected]073aabe2009-10-21 18:09:33311 ScheduleNextTask();
312 }
313
314 void ReadNonExistentInfo() {
315 EXPECT_FALSE(reader_->IsReadPending());
316 read_info_buffer_ = new HttpResponseInfoIOBuffer();
317 reader_->ReadInfo(read_info_buffer_, &read_info_callback_);
318 EXPECT_TRUE(reader_->IsReadPending());
319 expected_read_result_ = net::ERR_CACHE_MISS;
320 }
321
322 void ReadNonExistentData() {
323 EXPECT_FALSE(reader_->IsReadPending());
324 read_buffer_ = new IOBuffer(kBlockSize);
325 reader_->ReadData(read_buffer_, kBlockSize, &read_callback_);
326 EXPECT_TRUE(reader_->IsReadPending());
327 expected_read_result_ = net::ERR_CACHE_MISS;
328 }
329
330 // LoadResponseInfo_Miss ----------------------------------------------------
331 void LoadResponseInfo_Miss() {
[email protected]79b15b22010-05-19 00:38:56332 PushNextTask(NewRunnableMethod(
333 this, &AppCacheResponseTest::LoadResponseInfo_Miss_Verify));
[email protected]dda06f82009-10-21 18:38:51334 service_->storage()->LoadResponseInfo(GURL(), kNoSuchResponseId,
[email protected]073aabe2009-10-21 18:09:33335 storage_delegate_.get());
336 }
337
338 void LoadResponseInfo_Miss_Verify() {
[email protected]dda06f82009-10-21 18:38:51339 EXPECT_EQ(kNoSuchResponseId, storage_delegate_->loaded_info_id_);
[email protected]073aabe2009-10-21 18:09:33340 EXPECT_TRUE(!storage_delegate_->loaded_info_.get());
341 TestFinished();
342 }
343
344 // LoadResponseInfo_Hit ----------------------------------------------------
345 void LoadResponseInfo_Hit() {
346 // This tests involves multiple async steps.
347 // 1. Write a response headers and body to storage
348 // a. headers
349 // b. body
350 // 2. Use LoadResponseInfo to read the response headers back out
[email protected]79b15b22010-05-19 00:38:56351 PushNextTask(NewRunnableMethod(
352 this, &AppCacheResponseTest::LoadResponseInfo_Hit_Step2));
[email protected]073aabe2009-10-21 18:09:33353 writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
354 written_response_id_ = writer_->response_id();
355 WriteBasicResponse();
356 }
357
358 void LoadResponseInfo_Hit_Step2() {
359 writer_.reset();
[email protected]79b15b22010-05-19 00:38:56360 PushNextTask(NewRunnableMethod(
361 this, &AppCacheResponseTest::LoadResponseInfo_Hit_Verify));
[email protected]073aabe2009-10-21 18:09:33362 service_->storage()->LoadResponseInfo(GURL(), written_response_id_,
363 storage_delegate_.get());
364 }
365
366 void LoadResponseInfo_Hit_Verify() {
367 EXPECT_EQ(written_response_id_, storage_delegate_->loaded_info_id_);
368 EXPECT_TRUE(storage_delegate_->loaded_info_.get());
369 EXPECT_TRUE(CompareHttpResponseInfos(
370 write_info_buffer_->http_info.get(),
371 storage_delegate_->loaded_info_->http_response_info()));
[email protected]fd2885a2010-03-17 22:02:28372 EXPECT_EQ(basic_response_size(),
373 storage_delegate_->loaded_info_->response_data_size());
[email protected]073aabe2009-10-21 18:09:33374 TestFinished();
375 }
376
[email protected]0dfeec32010-01-06 22:25:33377 // AmountWritten ----------------------------------------------------
378
379 void AmountWritten() {
380 static const char kHttpHeaders[] =
381 "HTTP/1.0 200 OK\0\0";
382 std::string raw_headers(kHttpHeaders, arraysize(kHttpHeaders));
383 net::HttpResponseInfo* head = MakeHttpResponseInfo(raw_headers);
384 int expected_amount_written =
385 GetHttpResponseInfoSize(head) + kNumBlocks * kBlockSize;
386
387 // Push tasks in reverse order.
[email protected]79b15b22010-05-19 00:38:56388 PushNextTask(NewRunnableMethod(
389 this, &AppCacheResponseTest::Verify_AmountWritten,
390 expected_amount_written));
[email protected]0dfeec32010-01-06 22:25:33391 for (int i = 0; i < kNumBlocks; ++i) {
[email protected]79b15b22010-05-19 00:38:56392 PushNextTask(NewRunnableMethod(
393 this, &AppCacheResponseTest::WriteOneBlock, kNumBlocks - i));
[email protected]0dfeec32010-01-06 22:25:33394 }
[email protected]79b15b22010-05-19 00:38:56395 PushNextTask(NewRunnableMethod(
396 this, &AppCacheResponseTest::WriteResponseHead, head));
[email protected]0dfeec32010-01-06 22:25:33397
398 writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
399 written_response_id_ = writer_->response_id();
400 ScheduleNextTask();
401 }
402
403 void Verify_AmountWritten(int expected_amount_written) {
404 EXPECT_EQ(expected_amount_written, writer_->amount_written());
405 TestFinished();
406 }
407
408
[email protected]073aabe2009-10-21 18:09:33409 // WriteThenVariouslyReadResponse -------------------------------------------
[email protected]073aabe2009-10-21 18:09:33410
411 void WriteThenVariouslyReadResponse() {
412 // This tests involves multiple async steps.
413 // 1. First, write a large body using multiple writes, we don't bother
414 // with a response head for this test.
415 // 2. Read the entire body, using multiple reads
416 // 3. Read the entire body, using one read.
417 // 4. Attempt to read beyond the EOF.
418 // 5. Read just a range.
419 // 6. Attempt to read beyond EOF of a range.
420
421 // Push tasks in reverse order
[email protected]79b15b22010-05-19 00:38:56422 PushNextTask(NewRunnableMethod(
423 this, &AppCacheResponseTest::ReadRangeFullyBeyondEOF));
424 PushNextTask(NewRunnableMethod(
425 this, &AppCacheResponseTest::ReadRangePartiallyBeyondEOF));
426 PushNextTask(NewRunnableMethod(
427 this, &AppCacheResponseTest::ReadPastEOF));
428 PushNextTask(NewRunnableMethod(
429 this, &AppCacheResponseTest::ReadRange));
430 PushNextTask(NewRunnableMethod(
431 this, &AppCacheResponseTest::ReadPastEOF));
432 PushNextTask(NewRunnableMethod(
433 this, &AppCacheResponseTest::ReadAllAtOnce));
434 PushNextTask(NewRunnableMethod(
435 this, &AppCacheResponseTest::ReadInBlocks));
436 PushNextTask(NewRunnableMethod(
437 this, &AppCacheResponseTest::WriteOutBlocks));
[email protected]073aabe2009-10-21 18:09:33438
439 // Get them going.
440 ScheduleNextTask();
441 }
442
443 void WriteOutBlocks() {
444 writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
445 written_response_id_ = writer_->response_id();
446 for (int i = 0; i < kNumBlocks; ++i) {
[email protected]79b15b22010-05-19 00:38:56447 PushNextTask(NewRunnableMethod(
448 this, &AppCacheResponseTest::WriteOneBlock, kNumBlocks - i));
[email protected]073aabe2009-10-21 18:09:33449 }
450 ScheduleNextTask();
451 }
452
453 void WriteOneBlock(int block_number) {
454 scoped_refptr<IOBuffer> io_buffer =
455 new IOBuffer(kBlockSize);
456 FillData(block_number, io_buffer->data(), kBlockSize);
457 WriteResponseBody(io_buffer, kBlockSize);
458 }
459
460 void ReadInBlocks() {
461 writer_.reset();
462 reader_.reset(service_->storage()->CreateResponseReader(
463 GURL(), written_response_id_));
464 for (int i = 0; i < kNumBlocks; ++i) {
[email protected]79b15b22010-05-19 00:38:56465 PushNextTask(NewRunnableMethod(
466 this, &AppCacheResponseTest::ReadOneBlock, kNumBlocks - i));
[email protected]073aabe2009-10-21 18:09:33467 }
468 ScheduleNextTask();
469 }
470
471 void ReadOneBlock(int block_number) {
[email protected]79b15b22010-05-19 00:38:56472 PushNextTask(NewRunnableMethod(
473 this, &AppCacheResponseTest::VerifyOneBlock, block_number));
[email protected]073aabe2009-10-21 18:09:33474 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
475 }
476
477 void VerifyOneBlock(int block_number) {
478 EXPECT_TRUE(CheckData(block_number, read_buffer_->data(), kBlockSize));
479 ScheduleNextTask();
480 }
481
482 void ReadAllAtOnce() {
[email protected]79b15b22010-05-19 00:38:56483 PushNextTask(NewRunnableMethod(
484 this, &AppCacheResponseTest::VerifyAllAtOnce));
[email protected]073aabe2009-10-21 18:09:33485 reader_.reset(service_->storage()->CreateResponseReader(
486 GURL(), written_response_id_));
487 int big_size = kNumBlocks * kBlockSize;
488 ReadResponseBody(new IOBuffer(big_size), big_size);
489 }
490
491 void VerifyAllAtOnce() {
492 char* p = read_buffer_->data();
493 for (int i = 0; i < kNumBlocks; ++i, p += kBlockSize)
494 EXPECT_TRUE(CheckData(i + 1, p, kBlockSize));
495 ScheduleNextTask();
496 }
497
498 void ReadPastEOF() {
499 EXPECT_FALSE(reader_->IsReadPending());
500 read_buffer_ = new IOBuffer(kBlockSize);
501 expected_read_result_ = 0;
502 reader_->ReadData(
503 read_buffer_, kBlockSize, &read_callback_);
504 }
505
506 void ReadRange() {
[email protected]79b15b22010-05-19 00:38:56507 PushNextTask(NewRunnableMethod(
508 this, &AppCacheResponseTest::VerifyRange));
[email protected]073aabe2009-10-21 18:09:33509 reader_.reset(service_->storage()->CreateResponseReader(
510 GURL(), written_response_id_));
511 reader_->SetReadRange(kBlockSize, kBlockSize);
512 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
513 }
514
515 void VerifyRange() {
516 EXPECT_TRUE(CheckData(2, read_buffer_->data(), kBlockSize));
517 ScheduleNextTask(); // ReadPastEOF is scheduled next
518 }
519
520 void ReadRangePartiallyBeyondEOF() {
[email protected]79b15b22010-05-19 00:38:56521 PushNextTask(NewRunnableMethod(
522 this, &AppCacheResponseTest::VerifyRangeBeyondEOF));
[email protected]073aabe2009-10-21 18:09:33523 reader_.reset(service_->storage()->CreateResponseReader(
524 GURL(), written_response_id_));
525 reader_->SetReadRange(kBlockSize, kNumBlocks * kBlockSize);
526 ReadResponseBody(new IOBuffer(kNumBlocks * kBlockSize),
527 kNumBlocks * kBlockSize);
528 expected_read_result_ = (kNumBlocks - 1) * kBlockSize;
529 }
530
531 void VerifyRangeBeyondEOF() {
532 // Just verify the first 1k
533 VerifyRange();
534 }
535
536 void ReadRangeFullyBeyondEOF() {
537 reader_.reset(service_->storage()->CreateResponseReader(
538 GURL(), written_response_id_));
539 reader_->SetReadRange((kNumBlocks * kBlockSize) + 1, kBlockSize);
540 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
541 expected_read_result_ = 0;
542 }
543
544 // IOChaining -------------------------------------------
545 void IOChaining() {
546 // 1. Write several blocks out initiating the subsequent write
547 // from within the completion callback of the previous write.
548 // 2. Read and verify several blocks in similarly chaining reads.
549
550 // Push tasks in reverse order
[email protected]79b15b22010-05-19 00:38:56551 PushNextTaskAsImmediate(NewRunnableMethod(
552 this, &AppCacheResponseTest::ReadInBlocksImmediately));
553 PushNextTaskAsImmediate(NewRunnableMethod(
554 this, &AppCacheResponseTest::WriteOutBlocksImmediately));
[email protected]073aabe2009-10-21 18:09:33555
556 // Get them going.
557 ScheduleNextTask();
558 }
559
560 void WriteOutBlocksImmediately() {
561 writer_.reset(service_->storage()->CreateResponseWriter(GURL()));
562 written_response_id_ = writer_->response_id();
563 for (int i = 0; i < kNumBlocks; ++i) {
[email protected]79b15b22010-05-19 00:38:56564 PushNextTaskAsImmediate(NewRunnableMethod(
565 this, &AppCacheResponseTest::WriteOneBlock, kNumBlocks - i));
[email protected]073aabe2009-10-21 18:09:33566 }
567 ScheduleNextTask();
568 }
569
570 void ReadInBlocksImmediately() {
571 writer_.reset();
572 reader_.reset(service_->storage()->CreateResponseReader(
573 GURL(), written_response_id_));
574 for (int i = 0; i < kNumBlocks; ++i) {
[email protected]79b15b22010-05-19 00:38:56575 PushNextTaskAsImmediate(NewRunnableMethod(
576 this, &AppCacheResponseTest::ReadOneBlockImmediately,
577 kNumBlocks - i));
[email protected]073aabe2009-10-21 18:09:33578 }
579 ScheduleNextTask();
580 }
581
582 void ReadOneBlockImmediately(int block_number) {
[email protected]79b15b22010-05-19 00:38:56583 PushNextTaskAsImmediate(NewRunnableMethod(
584 this, &AppCacheResponseTest::VerifyOneBlock, block_number));
[email protected]073aabe2009-10-21 18:09:33585 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
586 }
587
588 // DeleteWithinCallbacks -------------------------------------------
589 void DeleteWithinCallbacks() {
590 // 1. Write out a few blocks normally, and upon
591 // completion of the last write, delete the writer.
592 // 2. Read in a few blocks normally, and upon completion
593 // of the last read, delete the reader.
594
595 should_delete_reader_in_completion_callback_ = true;
596 reader_deletion_count_down_ = kNumBlocks;
597 should_delete_writer_in_completion_callback_ = true;
598 writer_deletion_count_down_ = kNumBlocks;
599
[email protected]79b15b22010-05-19 00:38:56600 PushNextTask(NewRunnableMethod(
601 this, &AppCacheResponseTest::ReadInBlocks));
602 PushNextTask(NewRunnableMethod(
603 this, &AppCacheResponseTest::WriteOutBlocks));
[email protected]073aabe2009-10-21 18:09:33604 ScheduleNextTask();
605 }
606
607 // DeleteWithIOPending -------------------------------------------
608 void DeleteWithIOPending() {
609 // 1. Write a few blocks normally.
610 // 2. Start a write, delete with it pending.
611 // 3. Start a read, delete with it pending.
[email protected]79b15b22010-05-19 00:38:56612 PushNextTask(NewRunnableMethod(
613 this, &AppCacheResponseTest::ReadThenDelete));
614 PushNextTask(NewRunnableMethod(
615 this, &AppCacheResponseTest::WriteThenDelete));
616 PushNextTask(NewRunnableMethod(
617 this, &AppCacheResponseTest::WriteOutBlocks));
[email protected]073aabe2009-10-21 18:09:33618 ScheduleNextTask();
619 }
620
621 void WriteThenDelete() {
622 write_callback_was_called_ = false;
623 WriteOneBlock(5);
624 EXPECT_TRUE(writer_->IsWritePending());
625 writer_.reset();
626 ScheduleNextTask();
627 }
628
629 void ReadThenDelete() {
630 read_callback_was_called_ = false;
631 reader_.reset(service_->storage()->CreateResponseReader(
632 GURL(), written_response_id_));
633 ReadResponseBody(new IOBuffer(kBlockSize), kBlockSize);
634 EXPECT_TRUE(reader_->IsReadPending());
635 reader_.reset();
636
637 // Wait a moment to verify no callbacks.
638 MessageLoop::current()->PostDelayedTask(FROM_HERE,
[email protected]79b15b22010-05-19 00:38:56639 NewRunnableMethod(this, &AppCacheResponseTest::VerifyNoCallbacks),
[email protected]073aabe2009-10-21 18:09:33640 10);
641 }
642
643 void VerifyNoCallbacks() {
644 EXPECT_TRUE(!write_callback_was_called_);
645 EXPECT_TRUE(!read_callback_was_called_);
646 TestFinished();
647 }
648
649 // Data members
650
[email protected]073aabe2009-10-21 18:09:33651 scoped_ptr<base::WaitableEvent> test_finished_event_;
652 scoped_ptr<MockStorageDelegate> storage_delegate_;
653 scoped_ptr<MockAppCacheService> service_;
654 std::stack<std::pair<Task*, bool> > task_stack_;
655
656 scoped_ptr<AppCacheResponseReader> reader_;
657 scoped_refptr<HttpResponseInfoIOBuffer> read_info_buffer_;
658 scoped_refptr<IOBuffer> read_buffer_;
659 int expected_read_result_;
660 net::CompletionCallbackImpl<AppCacheResponseTest> read_callback_;
661 net::CompletionCallbackImpl<AppCacheResponseTest> read_info_callback_;
662 bool should_delete_reader_in_completion_callback_;
663 int reader_deletion_count_down_;
664 bool read_callback_was_called_;
665
666 int64 written_response_id_;
667 scoped_ptr<AppCacheResponseWriter> writer_;
668 scoped_refptr<HttpResponseInfoIOBuffer> write_info_buffer_;
669 scoped_refptr<IOBuffer> write_buffer_;
670 int expected_write_result_;
671 net::CompletionCallbackImpl<AppCacheResponseTest> write_callback_;
672 net::CompletionCallbackImpl<AppCacheResponseTest> write_info_callback_;
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
[email protected]073aabe2009-10-21 18:09:33683TEST_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
[email protected]0dfeec32010-01-06 22:25:33695TEST_F(AppCacheResponseTest, AmountWritten) {
696 RunTestOnIOThread(&AppCacheResponseTest::AmountWritten);
697}
698
[email protected]073aabe2009-10-21 18:09:33699TEST_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 appcache
716
[email protected]79b15b22010-05-19 00:38:56717// AppCacheResponseTest is expected to always live longer than the
718// runnable methods. This lets us call NewRunnableMethod on its instances.
719template<>
720struct RunnableMethodTraits<appcache::AppCacheResponseTest> {
721 void RetainCallee(appcache::AppCacheResponseTest* obj) { }
722 void ReleaseCallee(appcache::AppCacheResponseTest* obj) { }
723};