Chromium Code Reviews| Index: net/http/http_response_body_drainer_unittest.cc |
| diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc |
| index d9b6492a5378ad55986d89375c2a53894e441bc9..50dc37ce0bc0d9f006c4a2ad3a3a59d5d585ad10 100644 |
| --- a/net/http/http_response_body_drainer_unittest.cc |
| +++ b/net/http/http_response_body_drainer_unittest.cc |
| @@ -38,7 +38,7 @@ class CloseResultWaiter { |
| waiting_for_result_(false) {} |
| int WaitForResult() { |
| - DCHECK(!waiting_for_result_); |
| + CHECK(!waiting_for_result_); |
| while (!have_result_) { |
| waiting_for_result_ = true; |
| MessageLoop::current()->Run(); |
| @@ -66,9 +66,12 @@ class MockHttpStream : public HttpStream { |
| public: |
| MockHttpStream(CloseResultWaiter* result_waiter) |
| : result_waiter_(result_waiter), |
| + buf_len_(0), |
| closed_(false), |
| stall_reads_forever_(false), |
| num_chunks_(0), |
| + is_sync_(false), |
| + is_last_chunk_zero_size_(false), |
| is_complete_(false), |
| ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {} |
| virtual ~MockHttpStream() {} |
| @@ -108,7 +111,7 @@ class MockHttpStream : public HttpStream { |
| virtual int ReadResponseBody(IOBuffer* buf, int buf_len, |
| const CompletionCallback& callback) OVERRIDE; |
| virtual void Close(bool not_reusable) OVERRIDE { |
| - DCHECK(!closed_); |
| + CHECK(!closed_); |
| closed_ = true; |
| result_waiter_->set_result(not_reusable); |
| } |
| @@ -126,11 +129,16 @@ class MockHttpStream : public HttpStream { |
| virtual void Drain(HttpNetworkSession*) OVERRIDE {} |
| // Methods to tweak/observer mock behavior: |
| - void StallReadsForever() { stall_reads_forever_ = true; } |
| + void set_stall_reads_forever() { stall_reads_forever_ = true; } |
| void set_num_chunks(int num_chunks) { num_chunks_ = num_chunks; } |
| + void set_sync() { is_sync_ = true; } |
| + |
| + void set_is_last_chunk_zero_size() { is_last_chunk_zero_size_ = true; } |
| + |
| private: |
| + int ReadInternal(IOBuffer* buf, int buf_len); |
| void CompleteRead(); |
| bool closed() const { return closed_; } |
| @@ -138,50 +146,63 @@ class MockHttpStream : public HttpStream { |
| CloseResultWaiter* const result_waiter_; |
| scoped_refptr<IOBuffer> user_buf_; |
| CompletionCallback callback_; |
| + int buf_len_; |
| bool closed_; |
| bool stall_reads_forever_; |
| int num_chunks_; |
| + bool is_sync_; |
| + bool is_last_chunk_zero_size_; |
| bool is_complete_; |
| base::WeakPtrFactory<MockHttpStream> weak_factory_; |
| }; |
| -int MockHttpStream::ReadResponseBody( |
| - IOBuffer* buf, int buf_len, const CompletionCallback& callback) { |
| - DCHECK(!callback.is_null()); |
| - DCHECK(callback_.is_null()); |
| - DCHECK(buf); |
| +int MockHttpStream::ReadResponseBody(IOBuffer* buf, |
| + int buf_len, |
| + const CompletionCallback& callback) { |
| + CHECK(!callback.is_null()); |
| + CHECK(callback_.is_null()); |
| + CHECK(buf); |
| if (stall_reads_forever_) |
| return ERR_IO_PENDING; |
| - if (num_chunks_ == 0) |
| + if (is_complete_) |
| return ERR_UNEXPECTED; |
| - if (buf_len > kMagicChunkSize && num_chunks_ > 1) { |
| + if (!is_sync_) { |
| user_buf_ = buf; |
| + buf_len_ = buf_len; |
| callback_ = callback; |
| MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind(&MockHttpStream::CompleteRead, weak_factory_.GetWeakPtr())); |
| return ERR_IO_PENDING; |
| + } else { |
| + return ReadInternal(buf, buf_len); |
| } |
| +} |
| - num_chunks_--; |
| - if (!num_chunks_) |
| +int MockHttpStream::ReadInternal(IOBuffer* buf, int buf_len) { |
| + if (num_chunks_ != 0) { |
|
mmenke
2012/10/16 16:32:24
I suggest you put the following here:
if (is_last
|
| + if (buf_len > kMagicChunkSize) |
| + buf_len = kMagicChunkSize; |
| + std::memset(buf->data(), 1, buf_len); |
| + num_chunks_--; |
| + if (!num_chunks_ && !is_last_chunk_zero_size_) |
| + is_complete_ = true; |
| + return buf_len; |
| + } else { |
| is_complete_ = true; |
| - |
| - return buf_len; |
| + return 0; |
| + } |
| } |
| void MockHttpStream::CompleteRead() { |
| - CompletionCallback callback = callback_; |
| - std::memset(user_buf_->data(), 1, kMagicChunkSize); |
| + int result = ReadInternal(user_buf_, buf_len_); |
| user_buf_ = NULL; |
| + CompletionCallback callback = callback_; |
| callback_.Reset(); |
| - num_chunks_--; |
| - if (!num_chunks_) |
| - is_complete_ = true; |
| - callback.Run(kMagicChunkSize); |
| + callback.Run(result); |
| } |
| class HttpResponseBodyDrainerTest : public testing::Test { |
| @@ -213,8 +234,16 @@ class HttpResponseBodyDrainerTest : public testing::Test { |
| HttpResponseBodyDrainer* const drainer_; // Deletes itself. |
| }; |
| -TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) { |
| +TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncSingleOK) { |
| mock_stream_->set_num_chunks(1); |
| + mock_stream_->set_sync(); |
| + drainer_->Start(session_); |
| + EXPECT_FALSE(result_waiter_.WaitForResult()); |
| +} |
| + |
| +TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) { |
| + mock_stream_->set_num_chunks(3); |
| + mock_stream_->set_sync(); |
| drainer_->Start(session_); |
| EXPECT_FALSE(result_waiter_.WaitForResult()); |
| } |
| @@ -225,6 +254,24 @@ TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) { |
| EXPECT_FALSE(result_waiter_.WaitForResult()); |
| } |
| +// Test the case when the final chunk is 0 bytes. This can happen when |
| +// the final 0-byte chunk of a chunk-encoded http response is read in a last |
| +// call to ReadResponseBody, after all data were returned from HttpStream. |
| +TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncEmptyChunk) { |
| + mock_stream_->set_num_chunks(3); |
| + mock_stream_->set_is_last_chunk_zero_size(); |
| + drainer_->Start(session_); |
| + EXPECT_FALSE(result_waiter_.WaitForResult()); |
| +} |
| + |
| +TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncEmptyChunk) { |
| + mock_stream_->set_num_chunks(4); |
| + mock_stream_->set_sync(); |
| + mock_stream_->set_is_last_chunk_zero_size(); |
| + drainer_->Start(session_); |
| + EXPECT_FALSE(result_waiter_.WaitForResult()); |
| +} |
| + |
| TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) { |
| mock_stream_->set_num_chunks( |
| HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize); |
| @@ -234,14 +281,14 @@ TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) { |
| TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) { |
| mock_stream_->set_num_chunks(2); |
| - mock_stream_->StallReadsForever(); |
| + mock_stream_->set_stall_reads_forever(); |
| drainer_->Start(session_); |
| EXPECT_TRUE(result_waiter_.WaitForResult()); |
| } |
| TEST_F(HttpResponseBodyDrainerTest, CancelledBySession) { |
| mock_stream_->set_num_chunks(2); |
| - mock_stream_->StallReadsForever(); |
| + mock_stream_->set_stall_reads_forever(); |
| drainer_->Start(session_); |
| // HttpNetworkSession should delete |drainer_|. |
| } |