- add sources.
[platform/framework/web/crosswalk.git] / src / net / http / http_response_body_drainer_unittest.cc
1 // Copyright (c) 2012 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.
4
5 #include "net/http/http_response_body_drainer.h"
6
7 #include <cstring>
8
9 #include "base/bind.h"
10 #include "base/compiler_specific.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/test_completion_callback.h"
16 #include "net/http/http_network_session.h"
17 #include "net/http/http_server_properties_impl.h"
18 #include "net/http/http_stream.h"
19 #include "net/proxy/proxy_service.h"
20 #include "net/ssl/ssl_config_service_defaults.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 namespace net {
24
25 namespace {
26
27 const int kMagicChunkSize = 1024;
28 COMPILE_ASSERT(
29     (HttpResponseBodyDrainer::kDrainBodyBufferSize % kMagicChunkSize) == 0,
30     chunk_size_needs_to_divide_evenly_into_buffer_size);
31
32 class CloseResultWaiter {
33  public:
34   CloseResultWaiter()
35       : result_(false),
36         have_result_(false),
37         waiting_for_result_(false) {}
38
39   int WaitForResult() {
40     CHECK(!waiting_for_result_);
41     while (!have_result_) {
42       waiting_for_result_ = true;
43       base::MessageLoop::current()->Run();
44       waiting_for_result_ = false;
45     }
46     return result_;
47   }
48
49   void set_result(bool result) {
50     result_ = result;
51     have_result_ = true;
52     if (waiting_for_result_)
53       base::MessageLoop::current()->Quit();
54   }
55
56  private:
57   int result_;
58   bool have_result_;
59   bool waiting_for_result_;
60
61   DISALLOW_COPY_AND_ASSIGN(CloseResultWaiter);
62 };
63
64 class MockHttpStream : public HttpStream {
65  public:
66   MockHttpStream(CloseResultWaiter* result_waiter)
67       : result_waiter_(result_waiter),
68         buf_len_(0),
69         closed_(false),
70         stall_reads_forever_(false),
71         num_chunks_(0),
72         is_sync_(false),
73         is_last_chunk_zero_size_(false),
74         is_complete_(false),
75         weak_factory_(this) {}
76   virtual ~MockHttpStream() {}
77
78   // HttpStream implementation.
79   virtual int InitializeStream(const HttpRequestInfo* request_info,
80                                RequestPriority priority,
81                                const BoundNetLog& net_log,
82                                const CompletionCallback& callback) OVERRIDE {
83     return ERR_UNEXPECTED;
84   }
85   virtual int SendRequest(const HttpRequestHeaders& request_headers,
86                           HttpResponseInfo* response,
87                           const CompletionCallback& callback) OVERRIDE {
88     return ERR_UNEXPECTED;
89   }
90   virtual UploadProgress GetUploadProgress() const OVERRIDE {
91     return UploadProgress();
92   }
93   virtual int ReadResponseHeaders(const CompletionCallback& callback) OVERRIDE {
94     return ERR_UNEXPECTED;
95   }
96   virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE {
97     return NULL;
98   }
99
100   virtual bool CanFindEndOfResponse() const OVERRIDE { return true; }
101   virtual bool IsConnectionReused() const OVERRIDE { return false; }
102   virtual void SetConnectionReused() OVERRIDE {}
103   virtual bool IsConnectionReusable() const OVERRIDE { return false; }
104   virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {}
105   virtual void GetSSLCertRequestInfo(
106       SSLCertRequestInfo* cert_request_info) OVERRIDE {}
107
108   // Mocked API
109   virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
110                                const CompletionCallback& callback) OVERRIDE;
111   virtual void Close(bool not_reusable) OVERRIDE {
112     CHECK(!closed_);
113     closed_ = true;
114     result_waiter_->set_result(not_reusable);
115   }
116
117   virtual HttpStream* RenewStreamForAuth() OVERRIDE {
118     return NULL;
119   }
120
121   virtual bool IsResponseBodyComplete() const OVERRIDE { return is_complete_; }
122
123   virtual bool IsSpdyHttpStream() const OVERRIDE { return false; }
124
125   virtual bool GetLoadTimingInfo(
126       LoadTimingInfo* load_timing_info) const OVERRIDE { return false; }
127
128   virtual void Drain(HttpNetworkSession*) OVERRIDE {}
129
130   virtual void SetPriority(RequestPriority priority) OVERRIDE {}
131
132   // Methods to tweak/observer mock behavior:
133   void set_stall_reads_forever() { stall_reads_forever_ = true; }
134
135   void set_num_chunks(int num_chunks) { num_chunks_ = num_chunks; }
136
137   void set_sync() { is_sync_ = true; }
138
139   void set_is_last_chunk_zero_size() { is_last_chunk_zero_size_ = true; }
140
141  private:
142   int ReadResponseBodyImpl(IOBuffer* buf, int buf_len);
143   void CompleteRead();
144
145   bool closed() const { return closed_; }
146
147   CloseResultWaiter* const result_waiter_;
148   scoped_refptr<IOBuffer> user_buf_;
149   CompletionCallback callback_;
150   int buf_len_;
151   bool closed_;
152   bool stall_reads_forever_;
153   int num_chunks_;
154   bool is_sync_;
155   bool is_last_chunk_zero_size_;
156   bool is_complete_;
157   base::WeakPtrFactory<MockHttpStream> weak_factory_;
158 };
159
160 int MockHttpStream::ReadResponseBody(IOBuffer* buf,
161                                      int buf_len,
162                                      const CompletionCallback& callback) {
163   CHECK(!callback.is_null());
164   CHECK(callback_.is_null());
165   CHECK(buf);
166
167   if (stall_reads_forever_)
168     return ERR_IO_PENDING;
169
170   if (is_complete_)
171     return ERR_UNEXPECTED;
172
173   if (!is_sync_) {
174     user_buf_ = buf;
175     buf_len_ = buf_len;
176     callback_ = callback;
177     base::MessageLoop::current()->PostTask(
178         FROM_HERE,
179         base::Bind(&MockHttpStream::CompleteRead, weak_factory_.GetWeakPtr()));
180     return ERR_IO_PENDING;
181   } else {
182     return ReadResponseBodyImpl(buf, buf_len);
183   }
184 }
185
186 int MockHttpStream::ReadResponseBodyImpl(IOBuffer* buf, int buf_len) {
187   if (is_last_chunk_zero_size_ && num_chunks_ == 1) {
188     buf_len = 0;
189   } else {
190     if (buf_len > kMagicChunkSize)
191       buf_len = kMagicChunkSize;
192     std::memset(buf->data(), 1, buf_len);
193   }
194   num_chunks_--;
195   if (!num_chunks_)
196     is_complete_ = true;
197
198   return buf_len;
199 }
200
201 void MockHttpStream::CompleteRead() {
202   int result = ReadResponseBodyImpl(user_buf_.get(), buf_len_);
203   user_buf_ = NULL;
204   CompletionCallback callback = callback_;
205   callback_.Reset();
206   callback.Run(result);
207 }
208
209 class HttpResponseBodyDrainerTest : public testing::Test {
210  protected:
211   HttpResponseBodyDrainerTest()
212       : proxy_service_(ProxyService::CreateDirect()),
213         ssl_config_service_(new SSLConfigServiceDefaults),
214         http_server_properties_(new HttpServerPropertiesImpl()),
215         session_(CreateNetworkSession()),
216         mock_stream_(new MockHttpStream(&result_waiter_)),
217         drainer_(new HttpResponseBodyDrainer(mock_stream_)) {}
218
219   virtual ~HttpResponseBodyDrainerTest() {}
220
221   HttpNetworkSession* CreateNetworkSession() const {
222     HttpNetworkSession::Params params;
223     params.proxy_service = proxy_service_.get();
224     params.ssl_config_service = ssl_config_service_.get();
225     params.http_server_properties = http_server_properties_->GetWeakPtr();
226     return new HttpNetworkSession(params);
227   }
228
229   scoped_ptr<ProxyService> proxy_service_;
230   scoped_refptr<SSLConfigService> ssl_config_service_;
231   scoped_ptr<HttpServerPropertiesImpl> http_server_properties_;
232   const scoped_refptr<HttpNetworkSession> session_;
233   CloseResultWaiter result_waiter_;
234   MockHttpStream* const mock_stream_;  // Owned by |drainer_|.
235   HttpResponseBodyDrainer* const drainer_;  // Deletes itself.
236 };
237
238 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncSingleOK) {
239   mock_stream_->set_num_chunks(1);
240   mock_stream_->set_sync();
241   drainer_->Start(session_.get());
242   EXPECT_FALSE(result_waiter_.WaitForResult());
243 }
244
245 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncOK) {
246   mock_stream_->set_num_chunks(3);
247   mock_stream_->set_sync();
248   drainer_->Start(session_.get());
249   EXPECT_FALSE(result_waiter_.WaitForResult());
250 }
251
252 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncOK) {
253   mock_stream_->set_num_chunks(3);
254   drainer_->Start(session_.get());
255   EXPECT_FALSE(result_waiter_.WaitForResult());
256 }
257
258 // Test the case when the final chunk is 0 bytes. This can happen when
259 // the final 0-byte chunk of a chunk-encoded http response is read in a last
260 // call to ReadResponseBody, after all data were returned from HttpStream.
261 TEST_F(HttpResponseBodyDrainerTest, DrainBodyAsyncEmptyChunk) {
262   mock_stream_->set_num_chunks(4);
263   mock_stream_->set_is_last_chunk_zero_size();
264   drainer_->Start(session_.get());
265   EXPECT_FALSE(result_waiter_.WaitForResult());
266 }
267
268 TEST_F(HttpResponseBodyDrainerTest, DrainBodySyncEmptyChunk) {
269   mock_stream_->set_num_chunks(4);
270   mock_stream_->set_sync();
271   mock_stream_->set_is_last_chunk_zero_size();
272   drainer_->Start(session_.get());
273   EXPECT_FALSE(result_waiter_.WaitForResult());
274 }
275
276 TEST_F(HttpResponseBodyDrainerTest, DrainBodySizeEqualsDrainBuffer) {
277   mock_stream_->set_num_chunks(
278       HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize);
279   drainer_->Start(session_.get());
280   EXPECT_FALSE(result_waiter_.WaitForResult());
281 }
282
283 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTimeOut) {
284   mock_stream_->set_num_chunks(2);
285   mock_stream_->set_stall_reads_forever();
286   drainer_->Start(session_.get());
287   EXPECT_TRUE(result_waiter_.WaitForResult());
288 }
289
290 TEST_F(HttpResponseBodyDrainerTest, CancelledBySession) {
291   mock_stream_->set_num_chunks(2);
292   mock_stream_->set_stall_reads_forever();
293   drainer_->Start(session_.get());
294   // HttpNetworkSession should delete |drainer_|.
295 }
296
297 TEST_F(HttpResponseBodyDrainerTest, DrainBodyTooLarge) {
298   int too_many_chunks =
299       HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize;
300   too_many_chunks += 1;  // Now it's too large.
301
302   mock_stream_->set_num_chunks(too_many_chunks);
303   drainer_->Start(session_.get());
304   EXPECT_TRUE(result_waiter_.WaitForResult());
305 }
306
307 TEST_F(HttpResponseBodyDrainerTest, StartBodyTooLarge) {
308   int too_many_chunks =
309       HttpResponseBodyDrainer::kDrainBodyBufferSize / kMagicChunkSize;
310   too_many_chunks += 1;  // Now it's too large.
311
312   mock_stream_->set_num_chunks(0);
313   drainer_->StartWithSize(session_.get(), too_many_chunks * kMagicChunkSize);
314   EXPECT_TRUE(result_waiter_.WaitForResult());
315 }
316
317 TEST_F(HttpResponseBodyDrainerTest, StartWithNothingToDo) {
318   mock_stream_->set_num_chunks(0);
319   drainer_->StartWithSize(session_.get(), 0);
320   EXPECT_FALSE(result_waiter_.WaitForResult());
321 }
322
323 }  // namespace
324
325 }  // namespace net