http_bridge_unittest.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2006-2008 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/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() {
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(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