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.
6 #include "base/lazy_instance.h"
7 #include "base/memory/weak_ptr.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "mojo/application/public/cpp/application_test_base.h"
11 #include "mojo/message_pump/message_pump_mojo.h"
12 #include "mojo/services/network/network_context.h"
13 #include "mojo/services/network/url_loader_impl.h"
14 #include "net/base/net_errors.h"
15 #include "net/url_request/url_request_job.h"
16 #include "net/url_request/url_request_job_factory_impl.h"
17 #include "net/url_request/url_request_status.h"
18 #include "net/url_request/url_request_test_util.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
24 class TestURLRequestJob
;
26 TestURLRequestJob
* g_current_job
= nullptr;
29 void PassA(A
* destination
, A value
) {
30 *destination
= value
.Pass();
33 class TestURLRequestJob
: public net::URLRequestJob
{
35 enum Status
{ CREATED
, STARTED
, READING
, COMPLETED
};
37 TestURLRequestJob(net::URLRequest
* request
,
38 net::NetworkDelegate
* network_delegate
)
39 : net::URLRequestJob(request
, network_delegate
),
42 CHECK(!g_current_job
);
46 Status
status() { return status_
; }
48 int buf_size() { return buf_size_
; }
50 void Start() override
{ status_
= STARTED
; }
52 bool ReadRawData(net::IOBuffer
* buf
, int buf_size
, int* bytes_read
) override
{
55 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING
, 0));
59 void NotifyHeadersComplete() { net::URLRequestJob::NotifyHeadersComplete(); }
61 void NotifyReadComplete(int bytes_read
) {
64 NotifyDone(net::URLRequestStatus(
65 net::URLRequestStatus::FromError(net::ERR_FAILED
)));
66 net::URLRequestJob::NotifyReadComplete(0);
67 } else if (bytes_read
== 0) {
69 NotifyDone(net::URLRequestStatus());
70 net::URLRequestJob::NotifyReadComplete(bytes_read
);
73 SetStatus(net::URLRequestStatus());
74 net::URLRequestJob::NotifyReadComplete(bytes_read
);
79 ~TestURLRequestJob() override
{
80 CHECK(g_current_job
== this);
81 g_current_job
= nullptr;
88 class TestProtocolHandler
: public net::URLRequestJobFactory::ProtocolHandler
{
90 net::URLRequestJob
* MaybeCreateJob(
91 net::URLRequest
* request
,
92 net::NetworkDelegate
* network_delegate
) const override
{
93 return new TestURLRequestJob(request
, network_delegate
);
96 ~TestProtocolHandler() override
{}
99 class UrlLoaderImplTest
: public test::ApplicationTestBase
{
101 UrlLoaderImplTest() : message_loop_(common::MessagePumpMojo::Create()) {}
104 bool ShouldCreateDefaultRunLoop() override
{
108 void SetUp() override
{
109 ApplicationTestBase::SetUp();
111 scoped_ptr
<net::TestURLRequestContext
> url_request_context(
112 new net::TestURLRequestContext(true));
113 ASSERT_TRUE(url_request_job_factory_
.SetProtocolHandler(
114 "http", make_scoped_ptr(new TestProtocolHandler())));
115 url_request_context
->set_job_factory(&url_request_job_factory_
);
116 url_request_context
->Init();
117 network_context_
.reset(new NetworkContext(url_request_context
.Pass()));
119 new URLLoaderImpl(network_context_
.get(),
120 GetProxy(&url_loader_proxy_
),
121 make_scoped_ptr
<mojo::AppRefCount
>(nullptr));
122 EXPECT_TRUE(IsUrlLoaderValid());
125 bool IsUrlLoaderValid() {
126 return network_context_
->GetURLLoaderCountForTesting() > 0u;
129 base::MessageLoop message_loop_
;
130 net::TestJobInterceptor
* job_interceptor_
;
131 net::URLRequestJobFactoryImpl url_request_job_factory_
;
132 scoped_ptr
<NetworkContext
> network_context_
;
133 URLLoaderPtr url_loader_proxy_
;
136 TEST_F(UrlLoaderImplTest
, ClosedBeforeAnyCall
) {
137 url_loader_proxy_
.reset();
138 base::RunLoop().RunUntilIdle();
140 EXPECT_FALSE(IsUrlLoaderValid());
143 TEST_F(UrlLoaderImplTest
, ClosedWhileWaitingOnTheNetwork
) {
144 URLRequestPtr
request(URLRequest::New());
145 request
->url
= "http://example.com";
147 URLResponsePtr response
;
148 url_loader_proxy_
->Start(request
.Pass(),
149 base::Bind(&PassA
<URLResponsePtr
>, &response
));
150 base::RunLoop().RunUntilIdle();
152 EXPECT_TRUE(IsUrlLoaderValid());
153 EXPECT_FALSE(response
);
154 ASSERT_TRUE(g_current_job
);
156 g_current_job
->NotifyHeadersComplete();
157 base::RunLoop().RunUntilIdle();
159 EXPECT_TRUE(IsUrlLoaderValid());
160 EXPECT_TRUE(response
);
161 EXPECT_EQ(TestURLRequestJob::READING
, g_current_job
->status());
163 url_loader_proxy_
.reset();
164 base::RunLoop().RunUntilIdle();
166 EXPECT_TRUE(IsUrlLoaderValid());
169 base::RunLoop().RunUntilIdle();
171 EXPECT_FALSE(IsUrlLoaderValid());
174 TEST_F(UrlLoaderImplTest
, ClosedWhileWaitingOnThePipeToBeWriteable
) {
175 URLRequestPtr
request(URLRequest::New());
176 request
->url
= "http://example.com";
178 URLResponsePtr response
;
179 url_loader_proxy_
->Start(request
.Pass(),
180 base::Bind(&PassA
<URLResponsePtr
>, &response
));
181 base::RunLoop().RunUntilIdle();
183 EXPECT_TRUE(IsUrlLoaderValid());
184 EXPECT_FALSE(response
);
185 ASSERT_TRUE(g_current_job
);
187 g_current_job
->NotifyHeadersComplete();
188 base::RunLoop().RunUntilIdle();
190 EXPECT_TRUE(IsUrlLoaderValid());
191 EXPECT_TRUE(response
);
192 EXPECT_EQ(TestURLRequestJob::READING
, g_current_job
->status());
194 while (g_current_job
->status() == TestURLRequestJob::READING
) {
195 g_current_job
->NotifyReadComplete(g_current_job
->buf_size());
196 base::RunLoop().RunUntilIdle();
199 EXPECT_EQ(TestURLRequestJob::STARTED
, g_current_job
->status());
201 url_loader_proxy_
.reset();
202 base::RunLoop().RunUntilIdle();
204 EXPECT_TRUE(IsUrlLoaderValid());
207 base::RunLoop().RunUntilIdle();
209 EXPECT_FALSE(IsUrlLoaderValid());
212 TEST_F(UrlLoaderImplTest
, RequestCompleted
) {
213 URLRequestPtr
request(URLRequest::New());
214 request
->url
= "http://example.com";
216 URLResponsePtr response
;
217 url_loader_proxy_
->Start(request
.Pass(),
218 base::Bind(&PassA
<URLResponsePtr
>, &response
));
219 base::RunLoop().RunUntilIdle();
221 EXPECT_TRUE(IsUrlLoaderValid());
222 EXPECT_FALSE(response
);
223 ASSERT_TRUE(g_current_job
);
225 g_current_job
->NotifyHeadersComplete();
226 base::RunLoop().RunUntilIdle();
228 EXPECT_TRUE(IsUrlLoaderValid());
229 EXPECT_TRUE(response
);
230 EXPECT_EQ(TestURLRequestJob::READING
, g_current_job
->status());
232 url_loader_proxy_
.reset();
233 base::RunLoop().RunUntilIdle();
235 EXPECT_TRUE(IsUrlLoaderValid());
237 g_current_job
->NotifyReadComplete(0);
238 base::RunLoop().RunUntilIdle();
240 EXPECT_FALSE(IsUrlLoaderValid());
243 TEST_F(UrlLoaderImplTest
, RequestFailed
) {
244 URLRequestPtr
request(URLRequest::New());
245 request
->url
= "http://example.com";
247 URLResponsePtr response
;
248 url_loader_proxy_
->Start(request
.Pass(),
249 base::Bind(&PassA
<URLResponsePtr
>, &response
));
250 base::RunLoop().RunUntilIdle();
252 EXPECT_TRUE(IsUrlLoaderValid());
253 EXPECT_FALSE(response
);
254 ASSERT_TRUE(g_current_job
);
256 g_current_job
->NotifyHeadersComplete();
257 base::RunLoop().RunUntilIdle();
259 EXPECT_TRUE(IsUrlLoaderValid());
260 EXPECT_TRUE(response
);
261 EXPECT_EQ(TestURLRequestJob::READING
, g_current_job
->status());
263 url_loader_proxy_
.reset();
264 base::RunLoop().RunUntilIdle();
266 EXPECT_TRUE(IsUrlLoaderValid());
268 g_current_job
->NotifyReadComplete(-1);
269 base::RunLoop().RunUntilIdle();
271 EXPECT_FALSE(IsUrlLoaderValid());