OLD | NEW |
(Empty) | |
| 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/message_loop.h" |
| 11 #include "base/run_loop.h" |
| 12 #include "base/stringprintf.h" |
| 13 #include "net/url_request/url_request_job_factory_impl.h" |
| 14 #include "net/url_request/url_request_test_util.h" |
| 15 |
| 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 |
| 19 using android_webview::InputStream; |
| 20 using android_webview::InputStreamReader; |
| 21 using net::TestDelegate; |
| 22 using net::TestJobInterceptor; |
| 23 using net::TestNetworkDelegate; |
| 24 using net::TestURLRequestContext; |
| 25 using net::TestURLRequest; |
| 26 using testing::DoAll; |
| 27 using testing::Ge; |
| 28 using testing::Gt; |
| 29 using testing::InSequence; |
| 30 using testing::Invoke; |
| 31 using testing::InvokeWithoutArgs; |
| 32 using testing::NotNull; |
| 33 using testing::Return; |
| 34 using testing::SaveArg; |
| 35 using testing::SetArgPointee; |
| 36 using testing::StrictMock; |
| 37 using testing::Test; |
| 38 using testing::WithArg; |
| 39 using testing::WithArgs; |
| 40 using testing::_; |
| 41 |
| 42 // Some of the classes will DCHECK on a null InputStream (which is desirable). |
| 43 // The workaround is to use this class. None of the methods need to be |
| 44 // implemented as the mock InputStreamReader should never forward calls to the |
| 45 // InputStream. |
| 46 class NotImplInputStream : public InputStream { |
| 47 public: |
| 48 NotImplInputStream() {} |
| 49 virtual ~NotImplInputStream() {} |
| 50 virtual bool BytesAvailable(int* bytes_available) const { |
| 51 NOTIMPLEMENTED(); |
| 52 return false; |
| 53 } |
| 54 virtual bool Skip(int64_t n, int64_t* bytes_skipped) { |
| 55 NOTIMPLEMENTED(); |
| 56 return false; |
| 57 } |
| 58 virtual bool Read(net::IOBuffer* dest, int length, int* bytes_read) { |
| 59 NOTIMPLEMENTED(); |
| 60 return false; |
| 61 } |
| 62 }; |
| 63 |
| 64 // Required in order to create an instance of AndroidStreamReaderURLRequestJob. |
| 65 class StreamReaderDelegate : |
| 66 public AndroidStreamReaderURLRequestJob::Delegate { |
| 67 public: |
| 68 StreamReaderDelegate() {} |
| 69 |
| 70 virtual scoped_ptr<InputStream> OpenInputStream( |
| 71 JNIEnv* env, |
| 72 net::URLRequest* request) { |
| 73 return make_scoped_ptr<InputStream>(new NotImplInputStream()); |
| 74 } |
| 75 |
| 76 virtual bool GetMimeType( |
| 77 JNIEnv* env, |
| 78 net::URLRequest* request, |
| 79 const android_webview::InputStream& stream, |
| 80 std::string* mime_type) { |
| 81 return false; |
| 82 } |
| 83 |
| 84 virtual bool GetCharset( |
| 85 JNIEnv* env, |
| 86 net::URLRequest* request, |
| 87 const android_webview::InputStream& stream, |
| 88 std::string* charset) { |
| 89 return false; |
| 90 } |
| 91 }; |
| 92 |
| 93 class MockInputStreamReader : public InputStreamReader { |
| 94 public: |
| 95 MockInputStreamReader() : InputStreamReader(new NotImplInputStream()) {} |
| 96 |
| 97 MOCK_METHOD1(Seek, int(const net::HttpByteRange& byte_range)); |
| 98 |
| 99 MOCK_METHOD2(ReadRawData, int(net::IOBuffer* buffer, int buffer_size)); |
| 100 protected: |
| 101 ~MockInputStreamReader() {} |
| 102 }; |
| 103 |
| 104 |
| 105 class TestStreamReaderJob : public AndroidStreamReaderURLRequestJob { |
| 106 public: |
| 107 TestStreamReaderJob( |
| 108 net::URLRequest* request, |
| 109 net::NetworkDelegate* network_delegate, |
| 110 scoped_ptr<Delegate> delegate, |
| 111 scoped_refptr<InputStreamReader> stream_reader) |
| 112 : AndroidStreamReaderURLRequestJob(request, |
| 113 network_delegate, |
| 114 delegate.Pass()), |
| 115 stream_reader_(stream_reader) { |
| 116 message_loop_proxy_ = base::MessageLoopProxy::current(); |
| 117 } |
| 118 |
| 119 virtual scoped_refptr<InputStreamReader> CreateStreamReader( |
| 120 InputStream* stream) { |
| 121 return stream_reader_; |
| 122 } |
| 123 protected: |
| 124 virtual ~TestStreamReaderJob() {} |
| 125 |
| 126 virtual base::TaskRunner* GetWorkerThreadRunner() { |
| 127 return message_loop_proxy_.get(); |
| 128 } |
| 129 |
| 130 scoped_refptr<InputStreamReader> stream_reader_; |
| 131 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; |
| 132 }; |
| 133 |
| 134 class AndroidStreamReaderURLRequestJobTest : public Test { |
| 135 public: |
| 136 AndroidStreamReaderURLRequestJobTest() |
| 137 : loop_(MessageLoop::TYPE_IO) { |
| 138 } |
| 139 protected: |
| 140 virtual void SetUp() { |
| 141 context_.set_job_factory(&factory_); |
| 142 context_.set_network_delegate(&network_delegate_); |
| 143 req_.reset( |
| 144 new TestURLRequest(GURL("content://foo"), |
| 145 &url_request_delegate_, |
| 146 &context_)); |
| 147 req_->set_method("GET"); |
| 148 } |
| 149 |
| 150 void SetRange(net::URLRequest* req, int first_byte, int last_byte) { |
| 151 net::HttpRequestHeaders headers; |
| 152 headers.SetHeader(net::HttpRequestHeaders::kRange, |
| 153 base::StringPrintf( |
| 154 "bytes=%" PRIuS "-%" PRIuS, |
| 155 first_byte, last_byte)); |
| 156 req->SetExtraRequestHeaders(headers); |
| 157 } |
| 158 |
| 159 void SetUpTestJob(InputStreamReader* stream_reader) { |
| 160 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate> |
| 161 stream_reader_delegate(new StreamReaderDelegate()); |
| 162 TestStreamReaderJob* test_stream_reader_job = |
| 163 new TestStreamReaderJob( |
| 164 req_.get(), |
| 165 &network_delegate_, |
| 166 stream_reader_delegate.Pass(), |
| 167 stream_reader); |
| 168 // The Interceptor is owned by the |factory_|. |
| 169 TestJobInterceptor* interceptor = new TestJobInterceptor; |
| 170 interceptor->set_main_intercept_job(test_stream_reader_job); |
| 171 factory_.AddInterceptor(interceptor); |
| 172 } |
| 173 |
| 174 MessageLoop loop_; |
| 175 TestURLRequestContext context_; |
| 176 android_webview::AwURLRequestJobFactory factory_; |
| 177 TestDelegate url_request_delegate_; |
| 178 TestNetworkDelegate network_delegate_; |
| 179 scoped_ptr<TestURLRequest> req_; |
| 180 }; |
| 181 |
| 182 TEST_F(AndroidStreamReaderURLRequestJobTest, ReadEmptyStream) { |
| 183 scoped_refptr<StrictMock<MockInputStreamReader> > stream_reader = |
| 184 new StrictMock<MockInputStreamReader>(); |
| 185 { |
| 186 InSequence s; |
| 187 EXPECT_CALL(*stream_reader, Seek(_)) |
| 188 .WillOnce(Return(0)); |
| 189 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Gt(0))) |
| 190 .WillOnce(Return(0)); |
| 191 } |
| 192 |
| 193 SetUpTestJob(stream_reader); |
| 194 |
| 195 req_->Start(); |
| 196 |
| 197 // The TestDelegate will quit the message loop on request completion. |
| 198 MessageLoop::current()->Run(); |
| 199 |
| 200 EXPECT_FALSE(url_request_delegate_.request_failed()); |
| 201 EXPECT_EQ(1, network_delegate_.completed_requests()); |
| 202 } |
| 203 |
| 204 TEST_F(AndroidStreamReaderURLRequestJobTest, ReadPartOfStream) { |
| 205 const int bytes_available = 128; |
| 206 const int offset = 32; |
| 207 const int bytes_to_read = bytes_available - offset; |
| 208 scoped_refptr<StrictMock<MockInputStreamReader> > stream_reader = |
| 209 new StrictMock<MockInputStreamReader>(); |
| 210 { |
| 211 InSequence s; |
| 212 EXPECT_CALL(*stream_reader, Seek(_)) |
| 213 .WillOnce(Return(bytes_available)); |
| 214 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read))) |
| 215 .WillOnce(Return(bytes_to_read/2)); |
| 216 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read))) |
| 217 .WillOnce(Return(bytes_to_read/2)); |
| 218 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read))) |
| 219 .WillOnce(Return(0)); |
| 220 } |
| 221 |
| 222 SetUpTestJob(stream_reader); |
| 223 |
| 224 SetRange(req_.get(), offset, bytes_available); |
| 225 req_->Start(); |
| 226 |
| 227 MessageLoop::current()->Run(); |
| 228 |
| 229 EXPECT_FALSE(url_request_delegate_.request_failed()); |
| 230 EXPECT_EQ(bytes_to_read, url_request_delegate_.bytes_received()); |
| 231 EXPECT_EQ(1, network_delegate_.completed_requests()); |
| 232 } |
| 233 |
| 234 TEST_F(AndroidStreamReaderURLRequestJobTest, |
| 235 ReadStreamWithMoreAvailableThanActual) { |
| 236 const int bytes_available_reported = 190; |
| 237 const int bytes_available = 128; |
| 238 const int offset = 0; |
| 239 const int bytes_to_read = bytes_available - offset; |
| 240 scoped_refptr<StrictMock<MockInputStreamReader> > stream_reader = |
| 241 new StrictMock<MockInputStreamReader>(); |
| 242 { |
| 243 InSequence s; |
| 244 EXPECT_CALL(*stream_reader, Seek(_)) |
| 245 .WillOnce(Return(bytes_available_reported)); |
| 246 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read))) |
| 247 .WillOnce(Return(bytes_available)); |
| 248 EXPECT_CALL(*stream_reader, ReadRawData(NotNull(), Ge(bytes_to_read))) |
| 249 .WillOnce(Return(0)); |
| 250 } |
| 251 |
| 252 SetUpTestJob(stream_reader); |
| 253 |
| 254 SetRange(req_.get(), offset, bytes_available_reported); |
| 255 req_->Start(); |
| 256 |
| 257 MessageLoop::current()->Run(); |
| 258 |
| 259 EXPECT_FALSE(url_request_delegate_.request_failed()); |
| 260 EXPECT_EQ(bytes_to_read, url_request_delegate_.bytes_received()); |
| 261 EXPECT_EQ(1, network_delegate_.completed_requests()); |
| 262 } |
| 263 |
| 264 TEST_F(AndroidStreamReaderURLRequestJobTest, DeleteJobMidWaySeek) { |
| 265 const int offset = 20; |
| 266 const int bytes_available = 128; |
| 267 base::RunLoop loop; |
| 268 scoped_refptr<StrictMock<MockInputStreamReader> > stream_reader = |
| 269 new StrictMock<MockInputStreamReader>(); |
| 270 EXPECT_CALL(*stream_reader, Seek(_)) |
| 271 .WillOnce(DoAll(InvokeWithoutArgs(&loop, &base::RunLoop::Quit), |
| 272 Return(bytes_available))); |
| 273 ON_CALL(*stream_reader, ReadRawData(_, _)) |
| 274 .WillByDefault(Return(0)); |
| 275 |
| 276 SetUpTestJob(stream_reader); |
| 277 |
| 278 SetRange(req_.get(), offset, bytes_available); |
| 279 req_->Start(); |
| 280 |
| 281 loop.Run(); |
| 282 |
| 283 EXPECT_EQ(0, network_delegate_.completed_requests()); |
| 284 req_->Cancel(); |
| 285 EXPECT_EQ(1, network_delegate_.completed_requests()); |
| 286 } |
| 287 |
| 288 TEST_F(AndroidStreamReaderURLRequestJobTest, DeleteJobMidWayRead) { |
| 289 const int offset = 20; |
| 290 const int bytes_available = 128; |
| 291 base::RunLoop loop; |
| 292 scoped_refptr<StrictMock<MockInputStreamReader> > stream_reader = |
| 293 new StrictMock<MockInputStreamReader>(); |
| 294 net::CompletionCallback read_completion_callback; |
| 295 EXPECT_CALL(*stream_reader, Seek(_)) |
| 296 .WillOnce(Return(bytes_available)); |
| 297 EXPECT_CALL(*stream_reader, ReadRawData(_, _)) |
| 298 .WillOnce(DoAll(InvokeWithoutArgs(&loop, &base::RunLoop::Quit), |
| 299 Return(bytes_available))); |
| 300 |
| 301 SetUpTestJob(stream_reader); |
| 302 |
| 303 SetRange(req_.get(), offset, bytes_available); |
| 304 req_->Start(); |
| 305 |
| 306 loop.Run(); |
| 307 |
| 308 EXPECT_EQ(0, network_delegate_.completed_requests()); |
| 309 req_->Cancel(); |
| 310 EXPECT_EQ(1, network_delegate_.completed_requests()); |
| 311 } |
OLD | NEW |