Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 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 "base/message_loop_proxy.h"
      6 #include "base/threading/thread.h"
      7 #include "chrome/browser/sync/glue/http_bridge.h"
      8 #include "chrome/common/net/test_url_fetcher_factory.h"
      9 #include "chrome/test/test_url_request_context_getter.h"
     10 #include "content/browser/browser_thread.h"
     11 #include "net/url_request/url_request_test_util.h"
     12 #include "net/test/test_server.h"
     13 #include "testing/gtest/include/gtest/gtest.h"
     14 
     15 using browser_sync::HttpBridge;
     16 
     17 namespace {
     18 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113.
     19 const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
     20 }
     21 
     22 class HttpBridgeTest : public testing::Test {
     23  public:
     24   HttpBridgeTest()
     25       : test_server_(net::TestServer::TYPE_HTTP, FilePath(kDocRoot)),
     26         fake_default_request_context_getter_(NULL),
     27         io_thread_(BrowserThread::IO) {
     28   }
     29 
     30   virtual void SetUp() {
     31     base::Thread::Options options;
     32     options.message_loop_type = MessageLoop::TYPE_IO;
     33     io_thread_.StartWithOptions(options);
     34   }
     35 
     36   virtual void TearDown() {
     37     io_thread_loop()->ReleaseSoon(FROM_HERE,
     38         fake_default_request_context_getter_);
     39     io_thread_.Stop();
     40     fake_default_request_context_getter_ = NULL;
     41   }
     42 
     43   HttpBridge* BuildBridge() {
     44     if (!fake_default_request_context_getter_) {
     45       fake_default_request_context_getter_ = new TestURLRequestContextGetter();
     46       fake_default_request_context_getter_->AddRef();
     47     }
     48     HttpBridge* bridge = new HttpBridge(
     49         new HttpBridge::RequestContextGetter(
     50             fake_default_request_context_getter_));
     51     return bridge;
     52   }
     53 
     54   static void Abort(HttpBridge* bridge) {
     55     bridge->Abort();
     56   }
     57 
     58   static void TestSameHttpNetworkSession(MessageLoop* main_message_loop,
     59                                          HttpBridgeTest* test) {
     60     scoped_refptr<HttpBridge> http_bridge(test->BuildBridge());
     61     EXPECT_TRUE(test->GetTestRequestContextGetter());
     62     net::HttpNetworkSession* test_session =
     63         test->GetTestRequestContextGetter()->GetURLRequestContext()->
     64         http_transaction_factory()->GetSession();
     65     EXPECT_EQ(test_session,
     66               http_bridge->GetRequestContextGetter()->
     67                   GetURLRequestContext()->
     68                   http_transaction_factory()->GetSession());
     69     main_message_loop->PostTask(FROM_HERE, new MessageLoop::QuitTask);
     70   }
     71 
     72   MessageLoop* io_thread_loop() { return io_thread_.message_loop(); }
     73 
     74   // Note this is lazy created, so don't call this before your bridge.
     75   TestURLRequestContextGetter* GetTestRequestContextGetter() {
     76     return fake_default_request_context_getter_;
     77   }
     78 
     79   net::TestServer test_server_;
     80 
     81  private:
     82   // A make-believe "default" request context, as would be returned by
     83   // Profile::GetDefaultRequestContext().  Created lazily by BuildBridge.
     84   TestURLRequestContextGetter* fake_default_request_context_getter_;
     85 
     86   // Separate thread for IO used by the HttpBridge.
     87   BrowserThread io_thread_;
     88   MessageLoop loop_;
     89 };
     90 
     91 class DummyURLFetcher : public TestURLFetcher {
     92  public:
     93   DummyURLFetcher() : TestURLFetcher(0, GURL(), POST, NULL) {}
     94 
     95   net::HttpResponseHeaders* response_headers() const {
     96     return NULL;
     97   }
     98 };
     99 
    100 // An HttpBridge that doesn't actually make network requests and just calls
    101 // back with dummy response info.
    102 class ShuntedHttpBridge : public HttpBridge {
    103  public:
    104   // If |never_finishes| is true, the simulated request never actually
    105   // returns.
    106   ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter,
    107                     HttpBridgeTest* test, bool never_finishes)
    108       : HttpBridge(new HttpBridge::RequestContextGetter(
    109                        baseline_context_getter)),
    110                    test_(test), never_finishes_(never_finishes) { }
    111  protected:
    112   virtual void MakeAsynchronousPost() {
    113     ASSERT_TRUE(MessageLoop::current() == test_->io_thread_loop());
    114     if (never_finishes_)
    115       return;
    116 
    117     // We don't actually want to make a request for this test, so just callback
    118     // as if it completed.
    119     test_->io_thread_loop()->PostTask(FROM_HERE,
    120         NewRunnableMethod(this, &ShuntedHttpBridge::CallOnURLFetchComplete));
    121   }
    122  private:
    123   ~ShuntedHttpBridge() {}
    124 
    125   void CallOnURLFetchComplete() {
    126     ASSERT_TRUE(MessageLoop::current() == test_->io_thread_loop());
    127     // We return no cookies and a dummy content response.
    128     ResponseCookies cookies;
    129 
    130     std::string response_content = "success!";
    131     DummyURLFetcher fetcher;
    132     OnURLFetchComplete(&fetcher, GURL("www.google.com"),
    133                        net::URLRequestStatus(),
    134                        200, cookies, response_content);
    135   }
    136   HttpBridgeTest* test_;
    137   bool never_finishes_;
    138 };
    139 
    140 TEST_F(HttpBridgeTest, TestUsesSameHttpNetworkSession) {
    141   // Run this test on the IO thread because we can only call
    142   // URLRequestContextGetter::GetURLRequestContext on the IO thread.
    143   BrowserThread::PostTask(
    144       BrowserThread::IO, FROM_HERE,
    145       NewRunnableFunction(&HttpBridgeTest::TestSameHttpNetworkSession,
    146                           MessageLoop::current(), this));
    147   MessageLoop::current()->Run();
    148 }
    149 
    150 // Test the HttpBridge without actually making any network requests.
    151 TEST_F(HttpBridgeTest, TestMakeSynchronousPostShunted) {
    152   scoped_refptr<net::URLRequestContextGetter> ctx_getter(
    153       new TestURLRequestContextGetter());
    154   scoped_refptr<HttpBridge> http_bridge(new ShuntedHttpBridge(
    155       ctx_getter, this, false));
    156   http_bridge->SetUserAgent("bob");
    157   http_bridge->SetURL("http://www.google.com", 9999);
    158   http_bridge->SetPostPayload("text/plain", 2, " ");
    159 
    160   int os_error = 0;
    161   int response_code = 0;
    162   bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
    163   EXPECT_TRUE(success);
    164   EXPECT_EQ(200, response_code);
    165   EXPECT_EQ(0, os_error);
    166 
    167   EXPECT_EQ(8, http_bridge->GetResponseContentLength());
    168   EXPECT_EQ(std::string("success!"),
    169             std::string(http_bridge->GetResponseContent()));
    170 }
    171 
    172 // Full round-trip test of the HttpBridge, using default UA string and
    173 // no request cookies.
    174 TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
    175   ASSERT_TRUE(test_server_.Start());
    176 
    177   scoped_refptr<HttpBridge> http_bridge(BuildBridge());
    178 
    179   std::string payload = "this should be echoed back";
    180   GURL echo = test_server_.GetURL("echo");
    181   http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
    182   http_bridge->SetPostPayload("application/x-www-form-urlencoded",
    183                               payload.length() + 1, payload.c_str());
    184   int os_error = 0;
    185   int response_code = 0;
    186   bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
    187   EXPECT_TRUE(success);
    188   EXPECT_EQ(200, response_code);
    189   EXPECT_EQ(0, os_error);
    190 
    191   EXPECT_EQ(payload.length() + 1,
    192             static_cast<size_t>(http_bridge->GetResponseContentLength()));
    193   EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent()));
    194 }
    195 
    196 // Full round-trip test of the HttpBridge, using custom UA string
    197 TEST_F(HttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
    198   ASSERT_TRUE(test_server_.Start());
    199 
    200   scoped_refptr<HttpBridge> http_bridge(BuildBridge());
    201 
    202   GURL echo_header = test_server_.GetURL("echoall");
    203   http_bridge->SetUserAgent("bob");
    204   http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
    205 
    206   std::string test_payload = "###TEST PAYLOAD###";
    207   http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
    208                               test_payload.c_str());
    209 
    210   int os_error = 0;
    211   int response_code = 0;
    212   bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
    213   EXPECT_TRUE(success);
    214   EXPECT_EQ(200, response_code);
    215   EXPECT_EQ(0, os_error);
    216 
    217   std::string response(http_bridge->GetResponseContent(),
    218                        http_bridge->GetResponseContentLength());
    219   EXPECT_EQ(std::string::npos, response.find("Cookie:"));
    220   EXPECT_NE(std::string::npos, response.find("User-Agent: bob"));
    221   EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
    222 }
    223 
    224 TEST_F(HttpBridgeTest, TestExtraRequestHeaders) {
    225   ASSERT_TRUE(test_server_.Start());
    226 
    227   scoped_refptr<HttpBridge> http_bridge(BuildBridge());
    228 
    229   GURL echo_header = test_server_.GetURL("echoall");
    230 
    231   http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
    232   http_bridge->SetExtraRequestHeaders("test:fnord");
    233 
    234   std::string test_payload = "###TEST PAYLOAD###";
    235   http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
    236                               test_payload.c_str());
    237 
    238   int os_error = 0;
    239   int response_code = 0;
    240   bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
    241   EXPECT_TRUE(success);
    242   EXPECT_EQ(200, response_code);
    243   EXPECT_EQ(0, os_error);
    244 
    245   std::string response(http_bridge->GetResponseContent(),
    246                        http_bridge->GetResponseContentLength());
    247 
    248   EXPECT_NE(std::string::npos, response.find("fnord"));
    249   EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
    250 }
    251 
    252 TEST_F(HttpBridgeTest, TestResponseHeader) {
    253   ASSERT_TRUE(test_server_.Start());
    254 
    255   scoped_refptr<HttpBridge> http_bridge(BuildBridge());
    256 
    257   GURL echo_header = test_server_.GetURL("echoall");
    258   http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
    259 
    260   std::string test_payload = "###TEST PAYLOAD###";
    261   http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
    262                               test_payload.c_str());
    263 
    264   int os_error = 0;
    265   int response_code = 0;
    266   bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
    267   EXPECT_TRUE(success);
    268   EXPECT_EQ(200, response_code);
    269   EXPECT_EQ(0, os_error);
    270 
    271   EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html");
    272   EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty());
    273 }
    274 
    275 TEST_F(HttpBridgeTest, Abort) {
    276   scoped_refptr<net::URLRequestContextGetter> ctx_getter(
    277       new TestURLRequestContextGetter());
    278   scoped_refptr<ShuntedHttpBridge> http_bridge(new ShuntedHttpBridge(
    279       ctx_getter, this, true));
    280   http_bridge->SetUserAgent("bob");
    281   http_bridge->SetURL("http://www.google.com", 9999);
    282   http_bridge->SetPostPayload("text/plain", 2, " ");
    283 
    284   int os_error = 0;
    285   int response_code = 0;
    286 
    287   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, NewRunnableFunction(
    288                           &HttpBridgeTest::Abort, http_bridge));
    289   bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
    290   EXPECT_FALSE(success);
    291   EXPECT_EQ(net::ERR_ABORTED, os_error);
    292 }
    293 
    294 TEST_F(HttpBridgeTest, AbortLate) {
    295   scoped_refptr<net::URLRequestContextGetter> ctx_getter(
    296       new TestURLRequestContextGetter());
    297   scoped_refptr<ShuntedHttpBridge> http_bridge(new ShuntedHttpBridge(
    298       ctx_getter, this, false));
    299   http_bridge->SetUserAgent("bob");
    300   http_bridge->SetURL("http://www.google.com", 9999);
    301   http_bridge->SetPostPayload("text/plain", 2, " ");
    302 
    303   int os_error = 0;
    304   int response_code = 0;
    305 
    306   bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
    307   ASSERT_TRUE(success);
    308   http_bridge->Abort();
    309   // Ensures no double-free of URLFetcher, etc.
    310 }
    311