Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / android_webview / browser / net / android_stream_reader_url_request_job_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 "android_webview/browser/input_stream.h"
6 #include "android_webview/browser/net/android_stream_reader_url_request_job.h"
7 #include "android_webview/browser/net/aw_url_request_job_factory.h"
8 #include "android_webview/browser/net/input_stream_reader.h"
9 #include "base/format_macros.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "net/base/request_priority.h"
15 #include "net/http/http_byte_range.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_request.h"
18 #include "net/url_request/url_request_job_factory_impl.h"
19 #include "net/url_request/url_request_test_util.h"
20
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 using android_webview::InputStream;
25 using android_webview::InputStreamReader;
26 using net::TestDelegate;
27 using net::TestJobInterceptor;
28 using net::TestNetworkDelegate;
29 using net::TestURLRequestContext;
30 using net::URLRequest;
31 using testing::DoAll;
32 using testing::Ge;
33 using testing::Gt;
34 using testing::InSequence;
35 using testing::Invoke;
36 using testing::InvokeWithoutArgs;
37 using testing::NotNull;
38 using testing::Return;
39 using testing::SaveArg;
40 using testing::SetArgPointee;
41 using testing::StrictMock;
42 using testing::Test;
43 using testing::WithArg;
44 using testing::WithArgs;
45 using testing::_;
46
47 // Some of the classes will DCHECK on a null InputStream (which is desirable).
48 // The workaround is to use this class. None of the methods need to be
49 // implemented as the mock InputStreamReader should never forward calls to the
50 // InputStream.
51 class NotImplInputStream : public InputStream {
52  public:
53   NotImplInputStream() {}
54   virtual ~NotImplInputStream() {}
55   virtual bool BytesAvailable(int* bytes_available) const OVERRIDE {
56     NOTIMPLEMENTED();
57     return false;
58   }
59   virtual bool Skip(int64_t n, int64_t* bytes_skipped) OVERRIDE {
60     NOTIMPLEMENTED();
61     return false;
62   }
63   virtual bool Read(net::IOBuffer* dest, int length, int* bytes_read) OVERRIDE {
64     NOTIMPLEMENTED();
65     return false;
66   }
67 };
68
69 // Required in order to create an instance of AndroidStreamReaderURLRequestJob.
70 class StreamReaderDelegate :
71     public AndroidStreamReaderURLRequestJob::Delegate {
72  public:
73   StreamReaderDelegate() {}
74
75   virtual scoped_ptr<InputStream> OpenInputStream(
76       JNIEnv* env,
77       const GURL& url) OVERRIDE {
78     return make_scoped_ptr<InputStream>(new NotImplInputStream());
79   }
80
81   virtual void OnInputStreamOpenFailed(net::URLRequest* request,
82                                        bool* restart) OVERRIDE {
83     *restart = false;
84   }
85
86   virtual bool GetMimeType(JNIEnv* env,
87                            net::URLRequest* request,
88                            android_webview::InputStream* stream,
89                            std::string* mime_type) OVERRIDE {
90     return false;
91   }
92
93   virtual bool GetCharset(JNIEnv* env,
94                           net::URLRequest* request,
95                           android_webview::InputStream* stream,
96                           std::string* charset) OVERRIDE {
97     return false;
98   }
99
100   virtual void AppendResponseHeaders(
101       JNIEnv* env,
102       net::HttpResponseHeaders* headers) OVERRIDE {
103     // no-op
104   }
105 };
106
107 class NullStreamReaderDelegate : public StreamReaderDelegate {
108  public:
109   NullStreamReaderDelegate() {}
110
111   virtual scoped_ptr<InputStream> OpenInputStream(
112       JNIEnv* env,
113       const GURL& url) OVERRIDE {
114     return make_scoped_ptr<InputStream>(NULL);
115   }
116 };
117
118 class HeaderAlteringStreamReaderDelegate : public NullStreamReaderDelegate {
119  public:
120   HeaderAlteringStreamReaderDelegate() {}
121
122   virtual void AppendResponseHeaders(
123       JNIEnv* env,
124       net::HttpResponseHeaders* headers) OVERRIDE {
125     headers->ReplaceStatusLine(kStatusLine);
126     std::string headerLine(kCustomHeaderName);
127     headerLine.append(": ");
128     headerLine.append(kCustomHeaderValue);
129     headers->AddHeader(headerLine);
130   }
131
132   static const int kResponseCode;
133   static const char* kStatusLine;
134   static const char* kCustomHeaderName;
135   static const char* kCustomHeaderValue;
136 };
137
138 const int HeaderAlteringStreamReaderDelegate::kResponseCode = 401;
139 const char* HeaderAlteringStreamReaderDelegate::kStatusLine =
140     "HTTP/1.1 401 Gone";
141 const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderName =
142     "X-Test-Header";
143 const char* HeaderAlteringStreamReaderDelegate::kCustomHeaderValue =
144     "TestHeaderValue";
145
146 class MockInputStreamReader : public InputStreamReader {
147  public:
148   MockInputStreamReader() : InputStreamReader(new NotImplInputStream()) {}
149   ~MockInputStreamReader() {}
150
151   MOCK_METHOD1(Seek, int(const net::HttpByteRange& byte_range));
152   MOCK_METHOD2(ReadRawData, int(net::IOBuffer* buffer, int buffer_size));
153 };
154
155
156 class TestStreamReaderJob : public AndroidStreamReaderURLRequestJob {
157  public:
158   TestStreamReaderJob(
159       net::URLRequest* request,
160       net::NetworkDelegate* network_delegate,
161       scoped_ptr<Delegate> delegate,
162       scoped_ptr<InputStreamReader> stream_reader)
163       : AndroidStreamReaderURLRequestJob(request,
164                                          network_delegate,
165                                          delegate.Pass()),
166         stream_reader_(stream_reader.Pass()) {
167     message_loop_proxy_ = base::MessageLoopProxy::current();
168   }
169
170   virtual scoped_ptr<InputStreamReader> CreateStreamReader(
171       InputStream* stream) OVERRIDE {
172     return stream_reader_.Pass();
173   }
174  protected:
175   virtual ~TestStreamReaderJob() {}
176
177   virtual base::TaskRunner* GetWorkerThreadRunner() OVERRIDE {
178     return message_loop_proxy_.get();
179   }
180
181   scoped_ptr<InputStreamReader> stream_reader_;
182   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
183 };
184
185 class AndroidStreamReaderURLRequestJobTest : public Test {
186  public:
187   AndroidStreamReaderURLRequestJobTest() {}
188
189  protected:
190   virtual void SetUp() {
191     context_.set_job_factory(&factory_);
192     context_.set_network_delegate(&network_delegate_);
193     req_ = context_.CreateRequest(GURL("content://foo"),
194                                   net::DEFAULT_PRIORITY,
195                                   &url_request_delegate_,
196                                   NULL);
197     req_->set_method("GET");
198   }
199
200   void SetRange(net::URLRequest* req, int first_byte, int last_byte) {
201     net::HttpRequestHeaders headers;
202     headers.SetHeader(net::HttpRequestHeaders::kRange,
203                       net::HttpByteRange::Bounded(
204                           first_byte, last_byte).GetHeaderValue());
205     req->SetExtraRequestHeaders(headers);
206   }
207
208   void SetUpTestJob(scoped_ptr<InputStreamReader> stream_reader) {
209     SetUpTestJob(stream_reader.Pass(),
210                  make_scoped_ptr(new StreamReaderDelegate())
211                      .PassAs<AndroidStreamReaderURLRequestJob::Delegate>());
212   }
213
214   void SetUpTestJob(scoped_ptr<InputStreamReader> stream_reader,
215                     scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>
216                         stream_reader_delegate) {
217     TestStreamReaderJob* test_stream_reader_job =
218         new TestStreamReaderJob(
219             req_.get(),
220             &network_delegate_,
221             stream_reader_delegate.Pass(),
222             stream_reader.Pass());
223     // The Interceptor is owned by the |factory_|.
224     TestJobInterceptor* protocol_handler = new TestJobInterceptor;
225     protocol_handler->set_main_intercept_job(test_stream_reader_job);
226     bool set_protocol = factory_.SetProtocolHandler("http", protocol_handler);
227     DCHECK(set_protocol);
228
229     protocol_handler = new TestJobInterceptor;
230     protocol_handler->set_main_intercept_job(test_stream_reader_job);
231     set_protocol = factory_.SetProtocolHandler("content", protocol_handler);
232     DCHECK(set_protocol);
233   }
234
235   base::MessageLoopForIO loop_;
236   TestURLRequestContext context_;
237   android_webview::AwURLRequestJobFactory factory_;
238   TestDelegate url_request_delegate_;
239   TestNetworkDelegate network_delegate_;
240   scoped_ptr<URLRequest> req_;
241 };
242
243 TEST_F(AndroidStreamReaderURLRequestJobTest, ReadEmptyStream) {
244   scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
245       new StrictMock<MockInputStreamReader>());
246   {
247     InSequence s;
248     EXPECT_CALL(*stream_reader, Seek(_))
249         .WillOnce(Return(0));
250     EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Gt(0)))
251         .WillOnce(Return(0));
252   }
253
254   SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
255
256   req_->Start();
257
258   // The TestDelegate will quit the message loop on request completion.
259   base::MessageLoop::current()->Run();
260
261   EXPECT_FALSE(url_request_delegate_.request_failed());
262   EXPECT_EQ(1, network_delegate_.completed_requests());
263   EXPECT_EQ(0, network_delegate_.error_count());
264   EXPECT_EQ(200, req_->GetResponseCode());
265 }
266
267 TEST_F(AndroidStreamReaderURLRequestJobTest, ReadWithNullStream) {
268   SetUpTestJob(scoped_ptr<InputStreamReader>(),
269                make_scoped_ptr(new NullStreamReaderDelegate())
270                    .PassAs<AndroidStreamReaderURLRequestJob::Delegate>());
271   req_->Start();
272
273   // The TestDelegate will quit the message loop on request completion.
274   base::MessageLoop::current()->Run();
275
276   // The request_failed() method is named confusingly but all it checks is
277   // whether the request got as far as calling NotifyHeadersComplete.
278   EXPECT_FALSE(url_request_delegate_.request_failed());
279   EXPECT_EQ(1, network_delegate_.completed_requests());
280   // A null input stream shouldn't result in an error. See crbug.com/180950.
281   EXPECT_EQ(0, network_delegate_.error_count());
282   EXPECT_EQ(404, req_->GetResponseCode());
283 }
284
285 TEST_F(AndroidStreamReaderURLRequestJobTest, ModifyHeadersAndStatus) {
286   SetUpTestJob(scoped_ptr<InputStreamReader>(),
287                make_scoped_ptr(new HeaderAlteringStreamReaderDelegate())
288                    .PassAs<AndroidStreamReaderURLRequestJob::Delegate>());
289   req_->Start();
290
291   // The TestDelegate will quit the message loop on request completion.
292   base::MessageLoop::current()->Run();
293
294   // The request_failed() method is named confusingly but all it checks is
295   // whether the request got as far as calling NotifyHeadersComplete.
296   EXPECT_FALSE(url_request_delegate_.request_failed());
297   EXPECT_EQ(1, network_delegate_.completed_requests());
298   // A null input stream shouldn't result in an error. See crbug.com/180950.
299   EXPECT_EQ(0, network_delegate_.error_count());
300   EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kResponseCode,
301             req_->GetResponseCode());
302   EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kStatusLine,
303             req_->response_headers()->GetStatusLine());
304   EXPECT_TRUE(req_->response_headers()->HasHeader(
305       HeaderAlteringStreamReaderDelegate::kCustomHeaderName));
306   std::string header_value;
307   EXPECT_TRUE(req_->response_headers()->EnumerateHeader(
308       NULL, HeaderAlteringStreamReaderDelegate::kCustomHeaderName,
309       &header_value));
310   EXPECT_EQ(HeaderAlteringStreamReaderDelegate::kCustomHeaderValue,
311             header_value);
312 }
313
314 TEST_F(AndroidStreamReaderURLRequestJobTest, ReadPartOfStream) {
315   const int bytes_available = 128;
316   const int offset = 32;
317   const int bytes_to_read = bytes_available - offset;
318   scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
319       new StrictMock<MockInputStreamReader>());
320   {
321     InSequence s;
322     EXPECT_CALL(*stream_reader, Seek(_))
323         .WillOnce(Return(bytes_available));
324     EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
325         .WillOnce(Return(bytes_to_read/2));
326     EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
327         .WillOnce(Return(bytes_to_read/2));
328     EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
329         .WillOnce(Return(0));
330   }
331
332   SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
333
334   SetRange(req_.get(), offset, bytes_available);
335   req_->Start();
336
337   base::MessageLoop::current()->Run();
338
339   EXPECT_FALSE(url_request_delegate_.request_failed());
340   EXPECT_EQ(bytes_to_read, url_request_delegate_.bytes_received());
341   EXPECT_EQ(1, network_delegate_.completed_requests());
342   EXPECT_EQ(0, network_delegate_.error_count());
343 }
344
345 TEST_F(AndroidStreamReaderURLRequestJobTest,
346        ReadStreamWithMoreAvailableThanActual) {
347   const int bytes_available_reported = 190;
348   const int bytes_available = 128;
349   const int offset = 0;
350   const int bytes_to_read = bytes_available - offset;
351   scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
352       new StrictMock<MockInputStreamReader>());
353   {
354     InSequence s;
355     EXPECT_CALL(*stream_reader, Seek(_))
356         .WillOnce(Return(bytes_available_reported));
357     EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
358         .WillOnce(Return(bytes_available));
359     EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read)))
360         .WillOnce(Return(0));
361   }
362
363   SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
364
365   SetRange(req_.get(), offset, bytes_available_reported);
366   req_->Start();
367
368   base::MessageLoop::current()->Run();
369
370   EXPECT_FALSE(url_request_delegate_.request_failed());
371   EXPECT_EQ(bytes_to_read, url_request_delegate_.bytes_received());
372   EXPECT_EQ(1, network_delegate_.completed_requests());
373   EXPECT_EQ(0, network_delegate_.error_count());
374 }
375
376 TEST_F(AndroidStreamReaderURLRequestJobTest, DeleteJobMidWaySeek) {
377   const int offset = 20;
378   const int bytes_available = 128;
379   base::RunLoop loop;
380   scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
381       new StrictMock<MockInputStreamReader>());
382   EXPECT_CALL(*stream_reader, Seek(_))
383       .WillOnce(DoAll(InvokeWithoutArgs(&loop, &base::RunLoop::Quit),
384                       Return(bytes_available)));
385   ON_CALL(*stream_reader, ReadRawData(_, _))
386       .WillByDefault(Return(0));
387
388   SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
389
390   SetRange(req_.get(), offset, bytes_available);
391   req_->Start();
392
393   loop.Run();
394
395   EXPECT_EQ(0, network_delegate_.completed_requests());
396   req_->Cancel();
397   EXPECT_EQ(1, network_delegate_.completed_requests());
398 }
399
400 TEST_F(AndroidStreamReaderURLRequestJobTest, DeleteJobMidWayRead) {
401   const int offset = 20;
402   const int bytes_available = 128;
403   base::RunLoop loop;
404   scoped_ptr<StrictMock<MockInputStreamReader> > stream_reader(
405       new StrictMock<MockInputStreamReader>());
406   net::CompletionCallback read_completion_callback;
407   EXPECT_CALL(*stream_reader, Seek(_))
408       .WillOnce(Return(bytes_available));
409   EXPECT_CALL(*stream_reader, ReadRawData(_, _))
410       .WillOnce(DoAll(InvokeWithoutArgs(&loop, &base::RunLoop::Quit),
411                       Return(bytes_available)));
412
413   SetUpTestJob(stream_reader.PassAs<InputStreamReader>());
414
415   SetRange(req_.get(), offset, bytes_available);
416   req_->Start();
417
418   loop.Run();
419
420   EXPECT_EQ(0, network_delegate_.completed_requests());
421   req_->Cancel();
422   EXPECT_EQ(1, network_delegate_.completed_requests());
423 }