summaryrefslogtreecommitdiffstats
path: root/net/http/http_response_body_drainer_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/http/http_response_body_drainer_unittest.cc')
-rw-r--r--net/http/http_response_body_drainer_unittest.cc208
1 files changed, 208 insertions, 0 deletions
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc
new file mode 100644
index 0000000..41b4225
--- /dev/null
+++ b/net/http/http_response_body_drainer_unittest.cc
@@ -0,0 +1,208 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/http/http_response_body_drainer.h"
+
+#include "base/compiler_specific.h"
+#include "base/message_loop.h"
+#include "base/task.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/http/http_stream.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+const int kMagicChunkSize = 1024;
+COMPILE_ASSERT(
+ (HttpResponseBodyDrainer::kDrainBodyBufferSize % kMagicChunkSize) == 0,
+ chunk_size_needs_to_divide_evenly_into_buffer_size);
+
+class CloseResultWaiter {
+ public:
+ CloseResultWaiter()
+ : result_(false),
+ have_result_(false),
+ waiting_for_result_(false) {}
+
+ int WaitForResult() {
+ DCHECK(!waiting_for_result_);
+ while (!have_result_) {
+ waiting_for_result_ = true;
+ MessageLoop::current()->Run();
+ waiting_for_result_ = false;
+ }
+ return result_;
+ }
+
+ void set_result(bool result) {
+ result_ = result;
+ have_result_ = true;
+ if (waiting_for_result_)
+ MessageLoop::current()->Quit();
+ }
+
+ private:
+ int result_;
+ bool have_result_;
+ bool waiting_for_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseResultWaiter);
+};
+
+class MockHttpStream : public HttpStream {
+ public:
+ MockHttpStream(CloseResultWaiter* result_waiter)
+ : result_waiter_(result_waiter),
+ user_callback_(NULL),
+ closed_(false),
+ stall_reads_forever_(false),
+ num_chunks_(0),
+ is_complete_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
+ virtual ~MockHttpStream() {}
+
+ // HttpStream implementation:
+ virtual int InitializeStream(const HttpRequestInfo* request_info,
+ const BoundNetLog& net_log,
+ CompletionCallback* callback) {
+ return ERR_UNEXPECTED;
+ }
+ virtual int SendRequest(const std::string& request_headers,
+ UploadDataStream* request_body,
+ HttpResponseInfo* response,
+ CompletionCallback* callback) {
+ return ERR_UNEXPECTED;
+ }
+ virtual uint64 GetUploadProgress() const { return 0; }
+ virtual int ReadResponseHeaders(CompletionCallback* callback) {
+ return ERR_UNEXPECTED;
+ }
+ virtual const HttpResponseInfo* GetResponseInfo() const { return NULL; }
+
+ virtual bool CanFindEndOfResponse() const { return true; }
+ virtual bool IsMoreDataBuffered() const { return false; }
+ virtual bool IsConnectionReused() const { return false; }
+ virtual void SetConnectionReused() {}
+ virtual void GetSSLInfo(SSLInfo* ssl_info) {}
+ virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) {}
+
+ // Mocked API
+ virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
+ CompletionCallback* callback);
+ virtual void Close(bool not_reusable) {
+ DCHECK(!closed_);
+ closed_ = true;
+ result_waiter_->set_result(not_reusable);
+ }
+ virtual bool IsResponseBodyComplete() const { return is_complete_; }
+
+ // Methods to tweak/observer mock behavior:
+ void StallReadsForever() { stall_reads_forever_ = true; }
+
+ void set_num_chunks(int num_chunks) { num_chunks_ = num_chunks; }
+
+ private:
+ void CompleteRead();
+
+ bool closed() const { return closed_; }
+
+ CloseResultWaiter* const result_waiter_;
+ CompletionCallback* user_callback_;
+ bool closed_;
+ bool stall_reads_forever_;
+ int num_chunks_;
+ bool is_complete_;
+ ScopedRunnableMethodFactory<MockHttpStream> method_factory_;
+};
+
+int MockHttpStream::ReadResponseBody(
+ IOBuffer* buf, int buf_len, CompletionCallback* callback) {
+ DCHECK(callback);
+ DCHECK(!user_callback_);
+
+ if (stall_reads_forever_)
+ return ERR_IO_PENDING;
+
+ if (num_chunks_ == 0)
+ return ERR_UNEXPECTED;
+
+ if (buf_len > kMagicChunkSize && num_chunks_ > 1) {
+ user_callback_ = callback;
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(&MockHttpStream::CompleteRead));
+ return ERR_IO_PENDING;
+ }
+
+ num_chunks_--;
+ if (!num_chunks_)
+ is_complete_ = true;
+
+ return buf_len;
+}
+
+void MockHttpStream::CompleteRead() {
+ CompletionCallback* callback = user_callback_;
+ user_callback_ = NULL;
+ num_chunks_--;
+ if (!num_chunks_)
+ is_complete_ = true;
+ callback->Run(kMagicChunkSize);
+}
+
+class HttpResponseBodyDrainerTest : public testing::Test {
+ protected:
+ HttpResponseBodyDrainerTest()
+ : mock_stream_(new MockHttpStream(&result_waiter_)),
+ drainer_(new HttpResponseBodyDrainer(mock_stream_)) {}
+ ~HttpResponseBodyDrainerTest() {}
+
+ CloseResultWaiter result_waiter_;
+ MockHttpStream* const mock_stream_; // Owned by |drainer_|.
+ HttpResponseBodyDrainer* const drainer_; // Deletes itself.
+};
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) {
+ mock_stream_->set_num_chunks(1);
+ drainer_->Start();
+ EXPECT_FALSE(result_waiter_.WaitForResult());
+}
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) {
+ mock_stream_->set_num_chunks(3);
+ drainer_->Start();
+ EXPECT_FALSE(result_waiter_.WaitForResult());
+}
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) {
+ mock_stream_->set_num_chunks(
+ HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize);
+ drainer_->Start();
+ EXPECT_FALSE(result_waiter_.WaitForResult());
+}
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) {
+ mock_stream_->set_num_chunks(2);
+ mock_stream_->StallReadsForever();
+ drainer_->Start();
+ EXPECT_TRUE(result_waiter_.WaitForResult());
+}
+
+TEST_F(HttpResponseBodyDrainerTest, DrainBodyTooLarge) {
+ TestCompletionCallback callback;
+ int too_many_chunks =
+ HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize;
+ too_many_chunks += 1; // Now it's too large.
+
+ mock_stream_->set_num_chunks(too_many_chunks);
+ drainer_->Start();
+ EXPECT_TRUE(result_waiter_.WaitForResult());
+}
+
+} // namespace
+
+} // namespace net