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 "net/test/embedded_test_server/embedded_test_server.h" | |
6 | |
7 #include "base/path_service.h" | |
8 #include "base/strings/stringprintf.h" | |
9 #include "base/threading/thread.h" | |
10 #include "net/http/http_response_headers.h" | |
11 #include "net/test/embedded_test_server/http_request.h" | |
12 #include "net/test/embedded_test_server/http_response.h" | |
13 #include "net/url_request/url_fetcher.h" | |
14 #include "net/url_request/url_fetcher_delegate.h" | |
15 #include "net/url_request/url_request_test_util.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 namespace net { | |
19 namespace test_server { | |
20 | |
21 namespace { | |
22 | |
23 // Gets the content from the given URLFetcher. | |
24 std::string GetContentFromFetcher(const URLFetcher& fetcher) { | |
25 std::string result; | |
26 const bool success = fetcher.GetResponseAsString(&result); | |
27 EXPECT_TRUE(success); | |
28 return result; | |
29 } | |
30 | |
31 // Gets the content type from the given URLFetcher. | |
32 std::string GetContentTypeFromFetcher(const URLFetcher& fetcher) { | |
33 const HttpResponseHeaders* headers = fetcher.GetResponseHeaders(); | |
34 if (headers) { | |
35 std::string content_type; | |
36 if (headers->GetMimeType(&content_type)) | |
37 return content_type; | |
38 } | |
39 return std::string(); | |
40 } | |
41 | |
42 } // namespace | |
43 | |
44 class EmbeddedTestServerTest: public testing::Test, | |
45 public URLFetcherDelegate { | |
46 public: | |
47 EmbeddedTestServerTest() | |
48 : num_responses_received_(0), | |
49 num_responses_expected_(0), | |
50 io_thread_("io_thread") { | |
51 } | |
52 | |
53 void SetUp() override { | |
54 base::Thread::Options thread_options; | |
55 thread_options.message_loop_type = base::MessageLoop::TYPE_IO; | |
56 ASSERT_TRUE(io_thread_.StartWithOptions(thread_options)); | |
57 | |
58 request_context_getter_ = new TestURLRequestContextGetter( | |
59 io_thread_.message_loop_proxy()); | |
60 | |
61 server_.reset(new EmbeddedTestServer); | |
62 ASSERT_TRUE(server_->InitializeAndWaitUntilReady()); | |
63 } | |
64 | |
65 void TearDown() override { | |
66 ASSERT_TRUE(server_->ShutdownAndWaitUntilComplete()); | |
67 } | |
68 | |
69 // URLFetcherDelegate override. | |
70 void OnURLFetchComplete(const URLFetcher* source) override { | |
71 ++num_responses_received_; | |
72 if (num_responses_received_ == num_responses_expected_) | |
73 base::MessageLoop::current()->Quit(); | |
74 } | |
75 | |
76 // Waits until the specified number of responses are received. | |
77 void WaitForResponses(int num_responses) { | |
78 num_responses_received_ = 0; | |
79 num_responses_expected_ = num_responses; | |
80 // Will be terminated in OnURLFetchComplete(). | |
81 base::MessageLoop::current()->Run(); | |
82 } | |
83 | |
84 // Handles |request| sent to |path| and returns the response per |content|, | |
85 // |content type|, and |code|. Saves the request URL for verification. | |
86 scoped_ptr<HttpResponse> HandleRequest(const std::string& path, | |
87 const std::string& content, | |
88 const std::string& content_type, | |
89 HttpStatusCode code, | |
90 const HttpRequest& request) { | |
91 request_relative_url_ = request.relative_url; | |
92 | |
93 GURL absolute_url = server_->GetURL(request.relative_url); | |
94 if (absolute_url.path() == path) { | |
95 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
96 http_response->set_code(code); | |
97 http_response->set_content(content); | |
98 http_response->set_content_type(content_type); | |
99 return http_response.Pass(); | |
100 } | |
101 | |
102 return nullptr; | |
103 } | |
104 | |
105 protected: | |
106 int num_responses_received_; | |
107 int num_responses_expected_; | |
108 std::string request_relative_url_; | |
109 base::Thread io_thread_; | |
110 scoped_refptr<TestURLRequestContextGetter> request_context_getter_; | |
111 scoped_ptr<EmbeddedTestServer> server_; | |
112 }; | |
113 | |
114 TEST_F(EmbeddedTestServerTest, GetBaseURL) { | |
115 EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%u/", server_->port()), | |
116 server_->base_url().spec()); | |
117 } | |
118 | |
119 TEST_F(EmbeddedTestServerTest, GetURL) { | |
120 EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%u/path?query=foo", | |
121 server_->port()), | |
122 server_->GetURL("/path?query=foo").spec()); | |
123 } | |
124 | |
125 TEST_F(EmbeddedTestServerTest, GetURLWithHostname) { | |
126 EXPECT_EQ(base::StringPrintf("http://foo.com:%d/path?query=foo", | |
127 server_->port()), | |
128 server_->GetURL("foo.com", "/path?query=foo").spec()); | |
129 } | |
130 | |
131 TEST_F(EmbeddedTestServerTest, RegisterRequestHandler) { | |
132 server_->RegisterRequestHandler( | |
133 base::Bind(&EmbeddedTestServerTest::HandleRequest, | |
134 base::Unretained(this), | |
135 "/test", | |
136 "<b>Worked!</b>", | |
137 "text/html", | |
138 HTTP_OK)); | |
139 | |
140 scoped_ptr<URLFetcher> fetcher( | |
141 URLFetcher::Create(server_->GetURL("/test?q=foo"), | |
142 URLFetcher::GET, | |
143 this)); | |
144 fetcher->SetRequestContext(request_context_getter_.get()); | |
145 fetcher->Start(); | |
146 WaitForResponses(1); | |
147 | |
148 EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status()); | |
149 EXPECT_EQ(HTTP_OK, fetcher->GetResponseCode()); | |
150 EXPECT_EQ("<b>Worked!</b>", GetContentFromFetcher(*fetcher)); | |
151 EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher)); | |
152 | |
153 EXPECT_EQ("/test?q=foo", request_relative_url_); | |
154 } | |
155 | |
156 TEST_F(EmbeddedTestServerTest, ServeFilesFromDirectory) { | |
157 base::FilePath src_dir; | |
158 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)); | |
159 server_->ServeFilesFromDirectory( | |
160 src_dir.AppendASCII("net").AppendASCII("data")); | |
161 | |
162 scoped_ptr<URLFetcher> fetcher( | |
163 URLFetcher::Create(server_->GetURL("/test.html"), | |
164 URLFetcher::GET, | |
165 this)); | |
166 fetcher->SetRequestContext(request_context_getter_.get()); | |
167 fetcher->Start(); | |
168 WaitForResponses(1); | |
169 | |
170 EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status()); | |
171 EXPECT_EQ(HTTP_OK, fetcher->GetResponseCode()); | |
172 EXPECT_EQ("<p>Hello World!</p>", GetContentFromFetcher(*fetcher)); | |
173 EXPECT_EQ("", GetContentTypeFromFetcher(*fetcher)); | |
174 } | |
175 | |
176 TEST_F(EmbeddedTestServerTest, DefaultNotFoundResponse) { | |
177 scoped_ptr<URLFetcher> fetcher( | |
178 URLFetcher::Create(server_->GetURL("/non-existent"), | |
179 URLFetcher::GET, | |
180 this)); | |
181 fetcher->SetRequestContext(request_context_getter_.get()); | |
182 | |
183 fetcher->Start(); | |
184 WaitForResponses(1); | |
185 EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status()); | |
186 EXPECT_EQ(HTTP_NOT_FOUND, fetcher->GetResponseCode()); | |
187 } | |
188 | |
189 TEST_F(EmbeddedTestServerTest, ConcurrentFetches) { | |
190 server_->RegisterRequestHandler( | |
191 base::Bind(&EmbeddedTestServerTest::HandleRequest, | |
192 base::Unretained(this), | |
193 "/test1", | |
194 "Raspberry chocolate", | |
195 "text/html", | |
196 HTTP_OK)); | |
197 server_->RegisterRequestHandler( | |
198 base::Bind(&EmbeddedTestServerTest::HandleRequest, | |
199 base::Unretained(this), | |
200 "/test2", | |
201 "Vanilla chocolate", | |
202 "text/html", | |
203 HTTP_OK)); | |
204 server_->RegisterRequestHandler( | |
205 base::Bind(&EmbeddedTestServerTest::HandleRequest, | |
206 base::Unretained(this), | |
207 "/test3", | |
208 "No chocolates", | |
209 "text/plain", | |
210 HTTP_NOT_FOUND)); | |
211 | |
212 scoped_ptr<URLFetcher> fetcher1 = scoped_ptr<URLFetcher>( | |
213 URLFetcher::Create(server_->GetURL("/test1"), | |
214 URLFetcher::GET, | |
215 this)); | |
216 fetcher1->SetRequestContext(request_context_getter_.get()); | |
217 scoped_ptr<URLFetcher> fetcher2 = scoped_ptr<URLFetcher>( | |
218 URLFetcher::Create(server_->GetURL("/test2"), | |
219 URLFetcher::GET, | |
220 this)); | |
221 fetcher2->SetRequestContext(request_context_getter_.get()); | |
222 scoped_ptr<URLFetcher> fetcher3 = scoped_ptr<URLFetcher>( | |
223 URLFetcher::Create(server_->GetURL("/test3"), | |
224 URLFetcher::GET, | |
225 this)); | |
226 fetcher3->SetRequestContext(request_context_getter_.get()); | |
227 | |
228 // Fetch the three URLs concurrently. | |
229 fetcher1->Start(); | |
230 fetcher2->Start(); | |
231 fetcher3->Start(); | |
232 WaitForResponses(3); | |
233 | |
234 EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher1->GetStatus().status()); | |
235 EXPECT_EQ(HTTP_OK, fetcher1->GetResponseCode()); | |
236 EXPECT_EQ("Raspberry chocolate", GetContentFromFetcher(*fetcher1)); | |
237 EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher1)); | |
238 | |
239 EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher2->GetStatus().status()); | |
240 EXPECT_EQ(HTTP_OK, fetcher2->GetResponseCode()); | |
241 EXPECT_EQ("Vanilla chocolate", GetContentFromFetcher(*fetcher2)); | |
242 EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher2)); | |
243 | |
244 EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher3->GetStatus().status()); | |
245 EXPECT_EQ(HTTP_NOT_FOUND, fetcher3->GetResponseCode()); | |
246 EXPECT_EQ("No chocolates", GetContentFromFetcher(*fetcher3)); | |
247 EXPECT_EQ("text/plain", GetContentTypeFromFetcher(*fetcher3)); | |
248 } | |
249 | |
250 // Below test exercises EmbeddedTestServer's ability to cope with the situation | |
251 // where there is no MessageLoop available on the thread at EmbeddedTestServer | |
252 // initialization and/or destruction. | |
253 | |
254 typedef std::tr1::tuple<bool, bool> ThreadingTestParams; | |
255 | |
256 class EmbeddedTestServerThreadingTest | |
257 : public testing::TestWithParam<ThreadingTestParams> {}; | |
258 | |
259 class EmbeddedTestServerThreadingTestDelegate | |
260 : public base::PlatformThread::Delegate, | |
261 public URLFetcherDelegate { | |
262 public: | |
263 EmbeddedTestServerThreadingTestDelegate( | |
264 bool message_loop_present_on_initialize, | |
265 bool message_loop_present_on_shutdown) | |
266 : message_loop_present_on_initialize_(message_loop_present_on_initialize), | |
267 message_loop_present_on_shutdown_(message_loop_present_on_shutdown) {} | |
268 | |
269 // base::PlatformThread::Delegate: | |
270 void ThreadMain() override { | |
271 scoped_refptr<base::SingleThreadTaskRunner> io_thread_runner; | |
272 base::Thread io_thread("io_thread"); | |
273 base::Thread::Options thread_options; | |
274 thread_options.message_loop_type = base::MessageLoop::TYPE_IO; | |
275 ASSERT_TRUE(io_thread.StartWithOptions(thread_options)); | |
276 io_thread_runner = io_thread.message_loop_proxy(); | |
277 | |
278 scoped_ptr<base::MessageLoop> loop; | |
279 if (message_loop_present_on_initialize_) | |
280 loop.reset(new base::MessageLoopForIO); | |
281 | |
282 // Create the test server instance. | |
283 EmbeddedTestServer server; | |
284 base::FilePath src_dir; | |
285 ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)); | |
286 ASSERT_TRUE(server.InitializeAndWaitUntilReady()); | |
287 | |
288 // Make a request and wait for the reply. | |
289 if (!loop) | |
290 loop.reset(new base::MessageLoopForIO); | |
291 | |
292 scoped_ptr<URLFetcher> fetcher(URLFetcher::Create( | |
293 server.GetURL("/test?q=foo"), URLFetcher::GET, this)); | |
294 fetcher->SetRequestContext( | |
295 new TestURLRequestContextGetter(loop->message_loop_proxy())); | |
296 fetcher->Start(); | |
297 loop->Run(); | |
298 fetcher.reset(); | |
299 | |
300 // Shut down. | |
301 if (message_loop_present_on_shutdown_) | |
302 loop.reset(); | |
303 | |
304 ASSERT_TRUE(server.ShutdownAndWaitUntilComplete()); | |
305 } | |
306 | |
307 // URLFetcherDelegate override. | |
308 void OnURLFetchComplete(const URLFetcher* source) override { | |
309 base::MessageLoop::current()->Quit(); | |
310 } | |
311 | |
312 private: | |
313 bool message_loop_present_on_initialize_; | |
314 bool message_loop_present_on_shutdown_; | |
315 | |
316 DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServerThreadingTestDelegate); | |
317 }; | |
318 | |
319 TEST_P(EmbeddedTestServerThreadingTest, RunTest) { | |
320 // The actual test runs on a separate thread so it can screw with the presence | |
321 // of a MessageLoop - the test suite already sets up a MessageLoop for the | |
322 // main test thread. | |
323 base::PlatformThreadHandle thread_handle; | |
324 EmbeddedTestServerThreadingTestDelegate delegate( | |
325 std::tr1::get<0>(GetParam()), | |
326 std::tr1::get<1>(GetParam())); | |
327 ASSERT_TRUE(base::PlatformThread::Create(0, &delegate, &thread_handle)); | |
328 base::PlatformThread::Join(thread_handle); | |
329 } | |
330 | |
331 INSTANTIATE_TEST_CASE_P(EmbeddedTestServerThreadingTestInstantiation, | |
332 EmbeddedTestServerThreadingTest, | |
333 testing::Combine(testing::Bool(), testing::Bool())); | |
334 | |
335 } // namespace test_server | |
336 } // namespace net | |
OLD | NEW |