| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 <utility> | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/memory/weak_ptr.h" | |
| 10 #include "base/message_loop/message_loop.h" | |
| 11 #include "base/run_loop.h" | |
| 12 #include "mojo/message_pump/message_pump_mojo.h" | |
| 13 #include "mojo/public/cpp/bindings/interface_request.h" | |
| 14 #include "mojo/services/network/network_context.h" | |
| 15 #include "mojo/services/network/url_loader_impl.h" | |
| 16 #include "mojo/shell/public/cpp/message_loop_ref.h" | |
| 17 #include "mojo/shell/public/cpp/shell_test.h" | |
| 18 #include "net/base/net_errors.h" | |
| 19 #include "net/url_request/url_request_job.h" | |
| 20 #include "net/url_request/url_request_job_factory_impl.h" | |
| 21 #include "net/url_request/url_request_status.h" | |
| 22 #include "net/url_request/url_request_test_util.h" | |
| 23 #include "testing/gtest/include/gtest/gtest.h" | |
| 24 | |
| 25 namespace mojo { | |
| 26 | |
| 27 class TestURLRequestJob; | |
| 28 | |
| 29 TestURLRequestJob* g_current_job = nullptr; | |
| 30 | |
| 31 template <class A> | |
| 32 void PassA(A* destination, A value) { | |
| 33 *destination = std::move(value); | |
| 34 } | |
| 35 | |
| 36 class TestURLRequestJob : public net::URLRequestJob { | |
| 37 public: | |
| 38 enum Status { CREATED, STARTED, READING, COMPLETED }; | |
| 39 | |
| 40 TestURLRequestJob(net::URLRequest* request, | |
| 41 net::NetworkDelegate* network_delegate) | |
| 42 : net::URLRequestJob(request, network_delegate), | |
| 43 status_(CREATED), | |
| 44 buf_size_(0) { | |
| 45 CHECK(!g_current_job); | |
| 46 g_current_job = this; | |
| 47 } | |
| 48 | |
| 49 Status status() { return status_; } | |
| 50 | |
| 51 int buf_size() { return buf_size_; } | |
| 52 | |
| 53 void Start() override { status_ = STARTED; } | |
| 54 | |
| 55 int ReadRawData(net::IOBuffer* buf, int buf_size) override { | |
| 56 status_ = READING; | |
| 57 buf_size_ = buf_size; | |
| 58 return net::ERR_IO_PENDING; | |
| 59 } | |
| 60 | |
| 61 void NotifyHeadersComplete() { net::URLRequestJob::NotifyHeadersComplete(); } | |
| 62 | |
| 63 void NotifyReadComplete(int bytes_read) { | |
| 64 if (bytes_read < 0) { | |
| 65 // Map errors to net::ERR_FAILED. | |
| 66 ReadRawDataComplete(net::ERR_FAILED); | |
| 67 // Set this after calling ReadRawDataComplete since that ends up calling | |
| 68 // ReadRawData. | |
| 69 status_ = COMPLETED; | |
| 70 } else if (bytes_read == 0) { | |
| 71 ReadRawDataComplete(bytes_read); | |
| 72 // Set this after calling ReadRawDataComplete since that ends up calling | |
| 73 // ReadRawData. | |
| 74 status_ = COMPLETED; | |
| 75 } else { | |
| 76 ReadRawDataComplete(bytes_read); | |
| 77 // Set this after calling ReadRawDataComplete since that ends up calling | |
| 78 // ReadRawData. | |
| 79 status_ = STARTED; | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 private: | |
| 84 ~TestURLRequestJob() override { | |
| 85 CHECK(g_current_job == this); | |
| 86 g_current_job = nullptr; | |
| 87 } | |
| 88 | |
| 89 Status status_; | |
| 90 int buf_size_; | |
| 91 }; | |
| 92 | |
| 93 class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { | |
| 94 public: | |
| 95 explicit TestProtocolHandler(const base::Closure& quit_closure) | |
| 96 : quit_closure_(quit_closure) {} | |
| 97 net::URLRequestJob* MaybeCreateJob( | |
| 98 net::URLRequest* request, | |
| 99 net::NetworkDelegate* network_delegate) const override { | |
| 100 quit_closure_.Run(); | |
| 101 return new TestURLRequestJob(request, network_delegate); | |
| 102 } | |
| 103 | |
| 104 ~TestProtocolHandler() override {} | |
| 105 | |
| 106 private: | |
| 107 base::Closure quit_closure_; | |
| 108 }; | |
| 109 | |
| 110 class UrlLoaderImplTest : public test::ShellTest { | |
| 111 public: | |
| 112 UrlLoaderImplTest() : ShellTest("exe:network_service_unittests") {} | |
| 113 | |
| 114 protected: | |
| 115 void SetUp() override { | |
| 116 ShellTest::SetUp(); | |
| 117 | |
| 118 wait_for_request_.reset(new base::RunLoop); | |
| 119 | |
| 120 scoped_ptr<net::TestURLRequestContext> url_request_context( | |
| 121 new net::TestURLRequestContext(true)); | |
| 122 ASSERT_TRUE(url_request_job_factory_.SetProtocolHandler( | |
| 123 "http", make_scoped_ptr(new TestProtocolHandler( | |
| 124 wait_for_request_->QuitClosure())))); | |
| 125 url_request_context->set_job_factory(&url_request_job_factory_); | |
| 126 url_request_context->Init(); | |
| 127 network_context_.reset(new NetworkContext(std::move(url_request_context))); | |
| 128 MessagePipe pipe; | |
| 129 new URLLoaderImpl(network_context_.get(), | |
| 130 GetProxy(&url_loader_proxy_), | |
| 131 make_scoped_ptr<mojo::MessageLoopRef>(nullptr)); | |
| 132 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 133 } | |
| 134 | |
| 135 bool IsUrlLoaderValid() { | |
| 136 return network_context_->GetURLLoaderCountForTesting() > 0u; | |
| 137 } | |
| 138 | |
| 139 net::TestJobInterceptor* job_interceptor_; | |
| 140 net::URLRequestJobFactoryImpl url_request_job_factory_; | |
| 141 scoped_ptr<NetworkContext> network_context_; | |
| 142 URLLoaderPtr url_loader_proxy_; | |
| 143 scoped_ptr<base::RunLoop> wait_for_request_; | |
| 144 }; | |
| 145 | |
| 146 TEST_F(UrlLoaderImplTest, ClosedBeforeAnyCall) { | |
| 147 url_loader_proxy_.reset(); | |
| 148 | |
| 149 while (IsUrlLoaderValid()) | |
| 150 base::RunLoop().RunUntilIdle(); | |
| 151 } | |
| 152 | |
| 153 TEST_F(UrlLoaderImplTest, ClosedWhileWaitingOnTheNetwork) { | |
| 154 URLRequestPtr request(URLRequest::New()); | |
| 155 request->url = "http://example.com"; | |
| 156 | |
| 157 URLResponsePtr response; | |
| 158 url_loader_proxy_->Start(std::move(request), | |
| 159 base::Bind(&PassA<URLResponsePtr>, &response)); | |
| 160 wait_for_request_->Run(); | |
| 161 | |
| 162 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 163 EXPECT_FALSE(response); | |
| 164 ASSERT_TRUE(g_current_job); | |
| 165 | |
| 166 g_current_job->NotifyHeadersComplete(); | |
| 167 base::RunLoop().RunUntilIdle(); | |
| 168 | |
| 169 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 170 EXPECT_TRUE(response); | |
| 171 EXPECT_EQ(TestURLRequestJob::READING, g_current_job->status()); | |
| 172 | |
| 173 url_loader_proxy_.reset(); | |
| 174 base::RunLoop().RunUntilIdle(); | |
| 175 | |
| 176 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 177 | |
| 178 response.reset(); | |
| 179 | |
| 180 while (IsUrlLoaderValid()) | |
| 181 base::RunLoop().RunUntilIdle(); | |
| 182 } | |
| 183 | |
| 184 TEST_F(UrlLoaderImplTest, ClosedWhileWaitingOnThePipeToBeWriteable) { | |
| 185 URLRequestPtr request(URLRequest::New()); | |
| 186 request->url = "http://example.com"; | |
| 187 | |
| 188 URLResponsePtr response; | |
| 189 url_loader_proxy_->Start(std::move(request), | |
| 190 base::Bind(&PassA<URLResponsePtr>, &response)); | |
| 191 wait_for_request_->Run(); | |
| 192 | |
| 193 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 194 EXPECT_FALSE(response); | |
| 195 ASSERT_TRUE(g_current_job); | |
| 196 | |
| 197 g_current_job->NotifyHeadersComplete(); | |
| 198 while (g_current_job->status() != TestURLRequestJob::READING) | |
| 199 base::RunLoop().RunUntilIdle(); | |
| 200 | |
| 201 while (!response) | |
| 202 base::RunLoop().RunUntilIdle(); | |
| 203 | |
| 204 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 205 EXPECT_EQ(TestURLRequestJob::READING, g_current_job->status()); | |
| 206 | |
| 207 while (g_current_job->status() != TestURLRequestJob::STARTED) { | |
| 208 g_current_job->NotifyReadComplete(g_current_job->buf_size()); | |
| 209 base::RunLoop().RunUntilIdle(); | |
| 210 } | |
| 211 | |
| 212 EXPECT_EQ(TestURLRequestJob::STARTED, g_current_job->status()); | |
| 213 | |
| 214 url_loader_proxy_.reset(); | |
| 215 base::RunLoop().RunUntilIdle(); | |
| 216 | |
| 217 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 218 | |
| 219 response.reset(); | |
| 220 | |
| 221 while (IsUrlLoaderValid()) | |
| 222 base::RunLoop().RunUntilIdle(); | |
| 223 } | |
| 224 | |
| 225 TEST_F(UrlLoaderImplTest, RequestCompleted) { | |
| 226 URLRequestPtr request(URLRequest::New()); | |
| 227 request->url = "http://example.com"; | |
| 228 | |
| 229 URLResponsePtr response; | |
| 230 url_loader_proxy_->Start(std::move(request), | |
| 231 base::Bind(&PassA<URLResponsePtr>, &response)); | |
| 232 wait_for_request_->Run(); | |
| 233 | |
| 234 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 235 EXPECT_FALSE(response); | |
| 236 ASSERT_TRUE(g_current_job); | |
| 237 | |
| 238 g_current_job->NotifyHeadersComplete(); | |
| 239 base::RunLoop().RunUntilIdle(); | |
| 240 | |
| 241 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 242 EXPECT_TRUE(response); | |
| 243 EXPECT_EQ(TestURLRequestJob::READING, g_current_job->status()); | |
| 244 | |
| 245 url_loader_proxy_.reset(); | |
| 246 base::RunLoop().RunUntilIdle(); | |
| 247 | |
| 248 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 249 | |
| 250 g_current_job->NotifyReadComplete(0); | |
| 251 | |
| 252 while (IsUrlLoaderValid()) | |
| 253 base::RunLoop().RunUntilIdle(); | |
| 254 } | |
| 255 | |
| 256 TEST_F(UrlLoaderImplTest, RequestFailed) { | |
| 257 URLRequestPtr request(URLRequest::New()); | |
| 258 request->url = "http://example.com"; | |
| 259 | |
| 260 URLResponsePtr response; | |
| 261 url_loader_proxy_->Start(std::move(request), | |
| 262 base::Bind(&PassA<URLResponsePtr>, &response)); | |
| 263 wait_for_request_->Run(); | |
| 264 | |
| 265 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 266 EXPECT_FALSE(response); | |
| 267 ASSERT_TRUE(g_current_job); | |
| 268 | |
| 269 g_current_job->NotifyHeadersComplete(); | |
| 270 base::RunLoop().RunUntilIdle(); | |
| 271 | |
| 272 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 273 EXPECT_TRUE(response); | |
| 274 EXPECT_EQ(TestURLRequestJob::READING, g_current_job->status()); | |
| 275 | |
| 276 url_loader_proxy_.reset(); | |
| 277 base::RunLoop().RunUntilIdle(); | |
| 278 | |
| 279 EXPECT_TRUE(IsUrlLoaderValid()); | |
| 280 | |
| 281 g_current_job->NotifyReadComplete(-1); | |
| 282 | |
| 283 while (IsUrlLoaderValid()) | |
| 284 base::RunLoop().RunUntilIdle(); | |
| 285 } | |
| 286 | |
| 287 } // namespace mojo | |
| OLD | NEW |