Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(226)

Side by Side Diff: chrome/browser/sync/glue/http_bridge_unittest.cc

Issue 10645004: [Sync] Move HttpBridge to sync/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync to head Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/sync/glue/http_bridge.cc ('k') | chrome/browser/sync/glue/sync_backend_host.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 "base/message_loop_proxy.h"
6 #include "base/synchronization/waitable_event.h"
7 #include "base/threading/thread.h"
8 #include "chrome/browser/sync/glue/http_bridge.h"
9 #include "content/public/test/test_browser_thread.h"
10 #include "net/test/test_server.h"
11 #include "net/url_request/test_url_fetcher_factory.h"
12 #include "net/url_request/url_fetcher_delegate.h"
13 #include "net/url_request/url_request_test_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 using browser_sync::HttpBridge;
17 using content::BrowserThread;
18
19 namespace {
20 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113.
21 const FilePath::CharType kDocRoot[] = FILE_PATH_LITERAL("chrome/test/data");
22 }
23
24 class SyncHttpBridgeTest : public testing::Test {
25 public:
26 SyncHttpBridgeTest()
27 : test_server_(net::TestServer::TYPE_HTTP,
28 net::TestServer::kLocalhost,
29 FilePath(kDocRoot)),
30 fake_default_request_context_getter_(NULL),
31 bridge_for_race_test_(NULL),
32 io_thread_(BrowserThread::IO) {
33 }
34
35 virtual void SetUp() {
36 io_thread_.StartIOThread();
37 }
38
39 virtual void TearDown() {
40 if (fake_default_request_context_getter_) {
41 GetIOThreadLoop()->ReleaseSoon(FROM_HERE,
42 fake_default_request_context_getter_);
43 fake_default_request_context_getter_ = NULL;
44 }
45 io_thread_.Stop();
46 }
47
48 HttpBridge* BuildBridge() {
49 if (!fake_default_request_context_getter_) {
50 fake_default_request_context_getter_ =
51 new TestURLRequestContextGetter(
52 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
53 fake_default_request_context_getter_->AddRef();
54 }
55 HttpBridge* bridge = new HttpBridge(
56 new HttpBridge::RequestContextGetter(
57 fake_default_request_context_getter_));
58 return bridge;
59 }
60
61 static void Abort(HttpBridge* bridge) {
62 bridge->Abort();
63 }
64
65 // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race
66 // condition.
67 void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created,
68 base::WaitableEvent* signal_when_released);
69
70 static void TestSameHttpNetworkSession(MessageLoop* main_message_loop,
71 SyncHttpBridgeTest* test) {
72 scoped_refptr<HttpBridge> http_bridge(test->BuildBridge());
73 EXPECT_TRUE(test->GetTestRequestContextGetter());
74 net::HttpNetworkSession* test_session =
75 test->GetTestRequestContextGetter()->GetURLRequestContext()->
76 http_transaction_factory()->GetSession();
77 EXPECT_EQ(test_session,
78 http_bridge->GetRequestContextGetter()->
79 GetURLRequestContext()->
80 http_transaction_factory()->GetSession());
81 main_message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
82 }
83
84 MessageLoop* GetIOThreadLoop() {
85 return io_thread_.DeprecatedGetThreadObject()->message_loop();
86 }
87
88 // Note this is lazy created, so don't call this before your bridge.
89 TestURLRequestContextGetter* GetTestRequestContextGetter() {
90 return fake_default_request_context_getter_;
91 }
92
93 net::TestServer test_server_;
94
95 content::TestBrowserThread* io_thread() { return &io_thread_; }
96
97 HttpBridge* bridge_for_race_test() { return bridge_for_race_test_; }
98
99 private:
100 // A make-believe "default" request context, as would be returned by
101 // Profile::GetDefaultRequestContext(). Created lazily by BuildBridge.
102 TestURLRequestContextGetter* fake_default_request_context_getter_;
103
104 HttpBridge* bridge_for_race_test_;
105
106 // Separate thread for IO used by the HttpBridge.
107 content::TestBrowserThread io_thread_;
108 MessageLoop loop_;
109 };
110
111 // An HttpBridge that doesn't actually make network requests and just calls
112 // back with dummy response info.
113 // TODO(tim): Instead of inheriting here we should inject a component
114 // responsible for the MakeAsynchronousPost bit.
115 class ShuntedHttpBridge : public HttpBridge {
116 public:
117 // If |never_finishes| is true, the simulated request never actually
118 // returns.
119 ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter,
120 SyncHttpBridgeTest* test, bool never_finishes)
121 : HttpBridge(new HttpBridge::RequestContextGetter(
122 baseline_context_getter)),
123 test_(test), never_finishes_(never_finishes) { }
124 protected:
125 virtual void MakeAsynchronousPost() {
126 ASSERT_TRUE(MessageLoop::current() == test_->GetIOThreadLoop());
127 if (never_finishes_)
128 return;
129
130 // We don't actually want to make a request for this test, so just callback
131 // as if it completed.
132 test_->GetIOThreadLoop()->PostTask(FROM_HERE,
133 base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this));
134 }
135 private:
136 ~ShuntedHttpBridge() {}
137
138 void CallOnURLFetchComplete() {
139 ASSERT_TRUE(MessageLoop::current() == test_->GetIOThreadLoop());
140 // We return no cookies and a dummy content response.
141 net::ResponseCookies cookies;
142
143 std::string response_content = "success!";
144 net::TestURLFetcher fetcher(0, GURL(), NULL);
145 fetcher.set_url(GURL("www.google.com"));
146 fetcher.set_response_code(200);
147 fetcher.set_cookies(cookies);
148 fetcher.SetResponseString(response_content);
149 OnURLFetchComplete(&fetcher);
150 }
151 SyncHttpBridgeTest* test_;
152 bool never_finishes_;
153 };
154
155 void SyncHttpBridgeTest::RunSyncThreadBridgeUseTest(
156 base::WaitableEvent* signal_when_created,
157 base::WaitableEvent* signal_when_released) {
158 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
159 new TestURLRequestContextGetter(
160 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
161 {
162 scoped_refptr<ShuntedHttpBridge> bridge(new ShuntedHttpBridge(
163 ctx_getter, this, true));
164 bridge->SetUserAgent("bob");
165 bridge->SetURL("http://www.google.com", 9999);
166 bridge->SetPostPayload("text/plain", 2, " ");
167 bridge_for_race_test_ = bridge;
168 signal_when_created->Signal();
169
170 int os_error = 0;
171 int response_code = 0;
172 bridge->MakeSynchronousPost(&os_error, &response_code);
173 bridge_for_race_test_ = NULL;
174 }
175 signal_when_released->Signal();
176 }
177
178 TEST_F(SyncHttpBridgeTest, TestUsesSameHttpNetworkSession) {
179 // Run this test on the IO thread because we can only call
180 // URLRequestContextGetter::GetURLRequestContext on the IO thread.
181 BrowserThread::PostTask(
182 BrowserThread::IO, FROM_HERE,
183 base::Bind(&SyncHttpBridgeTest::TestSameHttpNetworkSession,
184 MessageLoop::current(), this));
185 MessageLoop::current()->Run();
186 }
187
188 // Test the HttpBridge without actually making any network requests.
189 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostShunted) {
190 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
191 new TestURLRequestContextGetter(
192 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
193 scoped_refptr<HttpBridge> http_bridge(new ShuntedHttpBridge(
194 ctx_getter, this, false));
195 http_bridge->SetUserAgent("bob");
196 http_bridge->SetURL("http://www.google.com", 9999);
197 http_bridge->SetPostPayload("text/plain", 2, " ");
198
199 int os_error = 0;
200 int response_code = 0;
201 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
202 EXPECT_TRUE(success);
203 EXPECT_EQ(200, response_code);
204 EXPECT_EQ(0, os_error);
205
206 EXPECT_EQ(8, http_bridge->GetResponseContentLength());
207 EXPECT_EQ(std::string("success!"),
208 std::string(http_bridge->GetResponseContent()));
209 }
210
211 // Full round-trip test of the HttpBridge, using default UA string and
212 // no request cookies.
213 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
214 ASSERT_TRUE(test_server_.Start());
215
216 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
217
218 std::string payload = "this should be echoed back";
219 GURL echo = test_server_.GetURL("echo");
220 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
221 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
222 payload.length() + 1, payload.c_str());
223 int os_error = 0;
224 int response_code = 0;
225 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
226 EXPECT_TRUE(success);
227 EXPECT_EQ(200, response_code);
228 EXPECT_EQ(0, os_error);
229
230 EXPECT_EQ(payload.length() + 1,
231 static_cast<size_t>(http_bridge->GetResponseContentLength()));
232 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent()));
233 }
234
235 // Full round-trip test of the HttpBridge, using custom UA string
236 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
237 ASSERT_TRUE(test_server_.Start());
238
239 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
240
241 GURL echo_header = test_server_.GetURL("echoall");
242 http_bridge->SetUserAgent("bob");
243 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
244
245 std::string test_payload = "###TEST PAYLOAD###";
246 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
247 test_payload.c_str());
248
249 int os_error = 0;
250 int response_code = 0;
251 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
252 EXPECT_TRUE(success);
253 EXPECT_EQ(200, response_code);
254 EXPECT_EQ(0, os_error);
255
256 std::string response(http_bridge->GetResponseContent(),
257 http_bridge->GetResponseContentLength());
258 EXPECT_EQ(std::string::npos, response.find("Cookie:"));
259 EXPECT_NE(std::string::npos, response.find("User-Agent: bob"));
260 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
261 }
262
263 TEST_F(SyncHttpBridgeTest, TestExtraRequestHeaders) {
264 ASSERT_TRUE(test_server_.Start());
265
266 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
267
268 GURL echo_header = test_server_.GetURL("echoall");
269
270 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
271 http_bridge->SetExtraRequestHeaders("test:fnord");
272
273 std::string test_payload = "###TEST PAYLOAD###";
274 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
275 test_payload.c_str());
276
277 int os_error = 0;
278 int response_code = 0;
279 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
280 EXPECT_TRUE(success);
281 EXPECT_EQ(200, response_code);
282 EXPECT_EQ(0, os_error);
283
284 std::string response(http_bridge->GetResponseContent(),
285 http_bridge->GetResponseContentLength());
286
287 EXPECT_NE(std::string::npos, response.find("fnord"));
288 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
289 }
290
291 TEST_F(SyncHttpBridgeTest, TestResponseHeader) {
292 ASSERT_TRUE(test_server_.Start());
293
294 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
295
296 GURL echo_header = test_server_.GetURL("echoall");
297 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
298
299 std::string test_payload = "###TEST PAYLOAD###";
300 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
301 test_payload.c_str());
302
303 int os_error = 0;
304 int response_code = 0;
305 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
306 EXPECT_TRUE(success);
307 EXPECT_EQ(200, response_code);
308 EXPECT_EQ(0, os_error);
309
310 EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html");
311 EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty());
312 }
313
314 TEST_F(SyncHttpBridgeTest, Abort) {
315 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
316 new TestURLRequestContextGetter(
317 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
318 scoped_refptr<ShuntedHttpBridge> http_bridge(new ShuntedHttpBridge(
319 ctx_getter, this, true));
320 http_bridge->SetUserAgent("bob");
321 http_bridge->SetURL("http://www.google.com", 9999);
322 http_bridge->SetPostPayload("text/plain", 2, " ");
323
324 int os_error = 0;
325 int response_code = 0;
326
327 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
328 base::Bind(&SyncHttpBridgeTest::Abort, http_bridge));
329 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
330 EXPECT_FALSE(success);
331 EXPECT_EQ(net::ERR_ABORTED, os_error);
332 }
333
334 TEST_F(SyncHttpBridgeTest, AbortLate) {
335 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
336 new TestURLRequestContextGetter(
337 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
338 scoped_refptr<ShuntedHttpBridge> http_bridge(new ShuntedHttpBridge(
339 ctx_getter, this, false));
340 http_bridge->SetUserAgent("bob");
341 http_bridge->SetURL("http://www.google.com", 9999);
342 http_bridge->SetPostPayload("text/plain", 2, " ");
343
344 int os_error = 0;
345 int response_code = 0;
346
347 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
348 ASSERT_TRUE(success);
349 http_bridge->Abort();
350 // Ensures no double-free of URLFetcher, etc.
351 }
352
353 // Tests an interesting case where code using the HttpBridge aborts the fetch
354 // and releases ownership before a pending fetch completed callback is issued by
355 // the underlying URLFetcher (and before that URLFetcher is destroyed, which
356 // would cancel the callback).
357 TEST_F(SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) {
358 base::Thread sync_thread("SyncThread");
359 sync_thread.Start();
360
361 // First, block the sync thread on the post.
362 base::WaitableEvent signal_when_created(false, false);
363 base::WaitableEvent signal_when_released(false, false);
364 sync_thread.message_loop()->PostTask(FROM_HERE,
365 base::Bind(&SyncHttpBridgeTest::RunSyncThreadBridgeUseTest,
366 base::Unretained(this),
367 &signal_when_created,
368 &signal_when_released));
369
370 // Stop IO so we can control order of operations.
371 base::WaitableEvent io_waiter(false, false);
372 ASSERT_TRUE(BrowserThread::PostTask(
373 BrowserThread::IO, FROM_HERE,
374 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter))));
375
376 signal_when_created.Wait(); // Wait till we have a bridge to abort.
377 ASSERT_TRUE(bridge_for_race_test());
378
379 // Schedule the fetch completion callback (but don't run it yet). Don't take
380 // a reference to the bridge to mimic URLFetcher's handling of the delegate.
381 net::URLFetcherDelegate* delegate =
382 static_cast<net::URLFetcherDelegate*>(bridge_for_race_test());
383 net::ResponseCookies cookies;
384 std::string response_content = "success!";
385 net::TestURLFetcher fetcher(0, GURL(), NULL);
386 fetcher.set_url(GURL("www.google.com"));
387 fetcher.set_response_code(200);
388 fetcher.set_cookies(cookies);
389 fetcher.SetResponseString(response_content);
390 ASSERT_TRUE(BrowserThread::PostTask(
391 BrowserThread::IO, FROM_HERE,
392 base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete,
393 base::Unretained(delegate), &fetcher)));
394
395 // Abort the fetch. This should be smart enough to handle the case where
396 // the bridge is destroyed before the callback scheduled above completes.
397 bridge_for_race_test()->Abort();
398
399 // Wait until the sync thread releases its ref on the bridge.
400 signal_when_released.Wait();
401 ASSERT_FALSE(bridge_for_race_test());
402
403 // Unleash the hounds. The fetch completion callback should fire first, and
404 // succeed even though we Release()d the bridge above because the call to
405 // Abort should have held a reference.
406 io_waiter.Signal();
407
408 // Done.
409 sync_thread.Stop();
410 io_thread()->Stop();
411 }
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/http_bridge.cc ('k') | chrome/browser/sync/glue/sync_backend_host.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698