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