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