root/net/test/embedded_test_server/embedded_test_server_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetContentFromFetcher
  2. GetContentTypeFromFetcher
  3. io_thread_
  4. SetUp
  5. TearDown
  6. OnURLFetchComplete
  7. WaitForResponses
  8. HandleRequest
  9. TEST_F
  10. TEST_F
  11. TEST_F
  12. TEST_F
  13. TEST_F
  14. TEST_F
  15. message_loop_present_on_shutdown_
  16. ThreadMain
  17. OnURLFetchComplete
  18. TEST_P

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/test/embedded_test_server/embedded_test_server.h"

#include "base/strings/stringprintf.h"
#include "base/threading/thread.h"
#include "net/http/http_response_headers.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {
namespace test_server {

namespace {

// Gets the content from the given URLFetcher.
std::string GetContentFromFetcher(const URLFetcher& fetcher) {
  std::string result;
  const bool success = fetcher.GetResponseAsString(&result);
  EXPECT_TRUE(success);
  return result;
}

// Gets the content type from the given URLFetcher.
std::string GetContentTypeFromFetcher(const URLFetcher& fetcher) {
  const HttpResponseHeaders* headers = fetcher.GetResponseHeaders();
  if (headers) {
    std::string content_type;
    if (headers->GetMimeType(&content_type))
      return content_type;
  }
  return std::string();
}

}  // namespace

class EmbeddedTestServerTest: public testing::Test,
                              public URLFetcherDelegate {
 public:
  EmbeddedTestServerTest()
      : num_responses_received_(0),
        num_responses_expected_(0),
        io_thread_("io_thread") {
  }

  virtual void SetUp() OVERRIDE {
    base::Thread::Options thread_options;
    thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
    ASSERT_TRUE(io_thread_.StartWithOptions(thread_options));

    request_context_getter_ = new TestURLRequestContextGetter(
        io_thread_.message_loop_proxy());

    server_.reset(new EmbeddedTestServer);
    ASSERT_TRUE(server_->InitializeAndWaitUntilReady());
  }

  virtual void TearDown() OVERRIDE {
    ASSERT_TRUE(server_->ShutdownAndWaitUntilComplete());
  }

  // URLFetcherDelegate override.
  virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE {
    ++num_responses_received_;
    if (num_responses_received_ == num_responses_expected_)
      base::MessageLoop::current()->Quit();
  }

  // Waits until the specified number of responses are received.
  void WaitForResponses(int num_responses) {
    num_responses_received_ = 0;
    num_responses_expected_ = num_responses;
    // Will be terminated in OnURLFetchComplete().
    base::MessageLoop::current()->Run();
  }

  // Handles |request| sent to |path| and returns the response per |content|,
  // |content type|, and |code|. Saves the request URL for verification.
  scoped_ptr<HttpResponse> HandleRequest(const std::string& path,
                                         const std::string& content,
                                         const std::string& content_type,
                                         HttpStatusCode code,
                                         const HttpRequest& request) {
    request_relative_url_ = request.relative_url;

    GURL absolute_url = server_->GetURL(request.relative_url);
    if (absolute_url.path() == path) {
      scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
      http_response->set_code(code);
      http_response->set_content(content);
      http_response->set_content_type(content_type);
      return http_response.PassAs<HttpResponse>();
    }

    return scoped_ptr<HttpResponse>();
  }

 protected:
  int num_responses_received_;
  int num_responses_expected_;
  std::string request_relative_url_;
  base::Thread io_thread_;
  scoped_refptr<TestURLRequestContextGetter> request_context_getter_;
  scoped_ptr<EmbeddedTestServer> server_;
};

TEST_F(EmbeddedTestServerTest, GetBaseURL) {
  EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/", server_->port()),
                               server_->base_url().spec());
}

TEST_F(EmbeddedTestServerTest, GetURL) {
  EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/path?query=foo",
                               server_->port()),
            server_->GetURL("/path?query=foo").spec());
}

TEST_F(EmbeddedTestServerTest, RegisterRequestHandler) {
  server_->RegisterRequestHandler(
      base::Bind(&EmbeddedTestServerTest::HandleRequest,
                 base::Unretained(this),
                 "/test",
                 "<b>Worked!</b>",
                 "text/html",
                 HTTP_OK));

  scoped_ptr<URLFetcher> fetcher(
      URLFetcher::Create(server_->GetURL("/test?q=foo"),
                              URLFetcher::GET,
                              this));
  fetcher->SetRequestContext(request_context_getter_.get());
  fetcher->Start();
  WaitForResponses(1);

  EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
  EXPECT_EQ(HTTP_OK, fetcher->GetResponseCode());
  EXPECT_EQ("<b>Worked!</b>", GetContentFromFetcher(*fetcher));
  EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher));

  EXPECT_EQ("/test?q=foo", request_relative_url_);
}

TEST_F(EmbeddedTestServerTest, ServeFilesFromDirectory) {
  base::FilePath src_dir;
  ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
  server_->ServeFilesFromDirectory(
      src_dir.AppendASCII("net").AppendASCII("data"));

  scoped_ptr<URLFetcher> fetcher(
      URLFetcher::Create(server_->GetURL("/test.html"),
                              URLFetcher::GET,
                              this));
  fetcher->SetRequestContext(request_context_getter_.get());
  fetcher->Start();
  WaitForResponses(1);

  EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
  EXPECT_EQ(HTTP_OK, fetcher->GetResponseCode());
  EXPECT_EQ("<p>Hello World!</p>", GetContentFromFetcher(*fetcher));
  EXPECT_EQ("", GetContentTypeFromFetcher(*fetcher));
}

TEST_F(EmbeddedTestServerTest, DefaultNotFoundResponse) {
  scoped_ptr<URLFetcher> fetcher(
      URLFetcher::Create(server_->GetURL("/non-existent"),
                              URLFetcher::GET,
                              this));
  fetcher->SetRequestContext(request_context_getter_.get());

  fetcher->Start();
  WaitForResponses(1);
  EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
  EXPECT_EQ(HTTP_NOT_FOUND, fetcher->GetResponseCode());
}

TEST_F(EmbeddedTestServerTest, ConcurrentFetches) {
  server_->RegisterRequestHandler(
      base::Bind(&EmbeddedTestServerTest::HandleRequest,
                 base::Unretained(this),
                 "/test1",
                 "Raspberry chocolate",
                 "text/html",
                 HTTP_OK));
  server_->RegisterRequestHandler(
      base::Bind(&EmbeddedTestServerTest::HandleRequest,
                 base::Unretained(this),
                 "/test2",
                 "Vanilla chocolate",
                 "text/html",
                 HTTP_OK));
  server_->RegisterRequestHandler(
      base::Bind(&EmbeddedTestServerTest::HandleRequest,
                 base::Unretained(this),
                 "/test3",
                 "No chocolates",
                 "text/plain",
                 HTTP_NOT_FOUND));

  scoped_ptr<URLFetcher> fetcher1 = scoped_ptr<URLFetcher>(
      URLFetcher::Create(server_->GetURL("/test1"),
                              URLFetcher::GET,
                              this));
  fetcher1->SetRequestContext(request_context_getter_.get());
  scoped_ptr<URLFetcher> fetcher2 = scoped_ptr<URLFetcher>(
      URLFetcher::Create(server_->GetURL("/test2"),
                              URLFetcher::GET,
                              this));
  fetcher2->SetRequestContext(request_context_getter_.get());
  scoped_ptr<URLFetcher> fetcher3 = scoped_ptr<URLFetcher>(
      URLFetcher::Create(server_->GetURL("/test3"),
                              URLFetcher::GET,
                              this));
  fetcher3->SetRequestContext(request_context_getter_.get());

  // Fetch the three URLs concurrently.
  fetcher1->Start();
  fetcher2->Start();
  fetcher3->Start();
  WaitForResponses(3);

  EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher1->GetStatus().status());
  EXPECT_EQ(HTTP_OK, fetcher1->GetResponseCode());
  EXPECT_EQ("Raspberry chocolate", GetContentFromFetcher(*fetcher1));
  EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher1));

  EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher2->GetStatus().status());
  EXPECT_EQ(HTTP_OK, fetcher2->GetResponseCode());
  EXPECT_EQ("Vanilla chocolate", GetContentFromFetcher(*fetcher2));
  EXPECT_EQ("text/html", GetContentTypeFromFetcher(*fetcher2));

  EXPECT_EQ(URLRequestStatus::SUCCESS, fetcher3->GetStatus().status());
  EXPECT_EQ(HTTP_NOT_FOUND, fetcher3->GetResponseCode());
  EXPECT_EQ("No chocolates", GetContentFromFetcher(*fetcher3));
  EXPECT_EQ("text/plain", GetContentTypeFromFetcher(*fetcher3));
}

// Below test exercises EmbeddedTestServer's ability to cope with the situation
// where there is no MessageLoop available on the thread at EmbeddedTestServer
// initialization and/or destruction.

typedef std::tr1::tuple<bool, bool> ThreadingTestParams;

class EmbeddedTestServerThreadingTest
    : public testing::TestWithParam<ThreadingTestParams> {};

class EmbeddedTestServerThreadingTestDelegate
    : public base::PlatformThread::Delegate,
      public URLFetcherDelegate {
 public:
  EmbeddedTestServerThreadingTestDelegate(
      bool message_loop_present_on_initialize,
      bool message_loop_present_on_shutdown)
      : message_loop_present_on_initialize_(message_loop_present_on_initialize),
        message_loop_present_on_shutdown_(message_loop_present_on_shutdown) {}

  // base::PlatformThread::Delegate:
  virtual void ThreadMain() OVERRIDE {
    scoped_refptr<base::SingleThreadTaskRunner> io_thread_runner;
    base::Thread io_thread("io_thread");
    base::Thread::Options thread_options;
    thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
    ASSERT_TRUE(io_thread.StartWithOptions(thread_options));
    io_thread_runner = io_thread.message_loop_proxy();

    scoped_ptr<base::MessageLoop> loop;
    if (message_loop_present_on_initialize_)
      loop.reset(new base::MessageLoopForIO);

    // Create the test server instance.
    EmbeddedTestServer server;
    base::FilePath src_dir;
    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_dir));
    ASSERT_TRUE(server.InitializeAndWaitUntilReady());

    // Make a request and wait for the reply.
    if (!loop)
      loop.reset(new base::MessageLoopForIO);

    scoped_ptr<URLFetcher> fetcher(URLFetcher::Create(
        server.GetURL("/test?q=foo"), URLFetcher::GET, this));
    fetcher->SetRequestContext(
        new TestURLRequestContextGetter(loop->message_loop_proxy()));
    fetcher->Start();
    loop->Run();
    fetcher.reset();

    // Shut down.
    if (message_loop_present_on_shutdown_)
      loop.reset();

    ASSERT_TRUE(server.ShutdownAndWaitUntilComplete());
  }

  // URLFetcherDelegate override.
  virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE {
    base::MessageLoop::current()->Quit();
  }

 private:
  bool message_loop_present_on_initialize_;
  bool message_loop_present_on_shutdown_;

  DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServerThreadingTestDelegate);
};

TEST_P(EmbeddedTestServerThreadingTest, RunTest) {
  // The actual test runs on a separate thread so it can screw with the presence
  // of a MessageLoop - the test suite already sets up a MessageLoop for the
  // main test thread.
  base::PlatformThreadHandle thread_handle;
  EmbeddedTestServerThreadingTestDelegate delegate(
      std::tr1::get<0>(GetParam()),
      std::tr1::get<1>(GetParam()));
  ASSERT_TRUE(base::PlatformThread::Create(0, &delegate, &thread_handle));
  base::PlatformThread::Join(thread_handle);
}

INSTANTIATE_TEST_CASE_P(EmbeddedTestServerThreadingTestInstantiation,
                        EmbeddedTestServerThreadingTest,
                        testing::Combine(testing::Bool(), testing::Bool()));

}  // namespace test_server
}  // namespace net

/* [<][>][^][v][top][bottom][index][help] */