Scroll-bar browser test.
[chromium-blink-merge.git] / sync / internal_api / http_bridge_unittest.cc
blob8a2c443a8585bd782022c4ee371f510742dd761f
1 // Copyright 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.
5 #include "base/synchronization/waitable_event.h"
6 #include "base/threading/thread.h"
7 #include "net/test/spawned_test_server/spawned_test_server.h"
8 #include "net/url_request/test_url_fetcher_factory.h"
9 #include "net/url_request/url_fetcher_delegate.h"
10 #include "net/url_request/url_request_test_util.h"
11 #include "sync/internal_api/public/base/cancelation_signal.h"
12 #include "sync/internal_api/public/http_bridge.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 namespace syncer {
17 namespace {
18 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113.
19 const base::FilePath::CharType kDocRoot[] =
20 FILE_PATH_LITERAL("chrome/test/data");
23 class SyncHttpBridgeTest : public testing::Test {
24 public:
25 SyncHttpBridgeTest()
26 : test_server_(net::SpawnedTestServer::TYPE_HTTP,
27 net::SpawnedTestServer::kLocalhost,
28 base::FilePath(kDocRoot)),
29 fake_default_request_context_getter_(NULL),
30 bridge_for_race_test_(NULL),
31 io_thread_("IO thread") {
34 virtual void SetUp() {
35 base::Thread::Options options;
36 options.message_loop_type = base::MessageLoop::TYPE_IO;
37 io_thread_.StartWithOptions(options);
40 virtual void TearDown() {
41 if (fake_default_request_context_getter_) {
42 GetIOThreadLoop()->ReleaseSoon(FROM_HERE,
43 fake_default_request_context_getter_);
44 fake_default_request_context_getter_ = NULL;
46 io_thread_.Stop();
49 HttpBridge* BuildBridge() {
50 if (!fake_default_request_context_getter_) {
51 fake_default_request_context_getter_ =
52 new net::TestURLRequestContextGetter(io_thread_.message_loop_proxy());
53 fake_default_request_context_getter_->AddRef();
55 HttpBridge* bridge = new HttpBridge(
56 new HttpBridge::RequestContextGetter(
57 fake_default_request_context_getter_,
58 "user agent"),
59 NetworkTimeUpdateCallback());
60 return bridge;
63 static void Abort(HttpBridge* bridge) {
64 bridge->Abort();
67 // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race
68 // condition.
69 void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created,
70 base::WaitableEvent* signal_when_released);
72 static void TestSameHttpNetworkSession(base::MessageLoop* main_message_loop,
73 SyncHttpBridgeTest* test) {
74 scoped_refptr<HttpBridge> http_bridge(test->BuildBridge());
75 EXPECT_TRUE(test->GetTestRequestContextGetter());
76 net::HttpNetworkSession* test_session =
77 test->GetTestRequestContextGetter()->GetURLRequestContext()->
78 http_transaction_factory()->GetSession();
79 EXPECT_EQ(test_session,
80 http_bridge->GetRequestContextGetterForTest()->
81 GetURLRequestContext()->
82 http_transaction_factory()->GetSession());
83 main_message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
86 base::MessageLoop* GetIOThreadLoop() { return io_thread_.message_loop(); }
88 // Note this is lazy created, so don't call this before your bridge.
89 net::TestURLRequestContextGetter* GetTestRequestContextGetter() {
90 return fake_default_request_context_getter_;
93 net::SpawnedTestServer test_server_;
95 base::Thread* io_thread() { return &io_thread_; }
97 HttpBridge* bridge_for_race_test() { return bridge_for_race_test_; }
99 private:
100 // A make-believe "default" request context, as would be returned by
101 // Profile::GetDefaultRequestContext(). Created lazily by BuildBridge.
102 net::TestURLRequestContextGetter* fake_default_request_context_getter_;
104 HttpBridge* bridge_for_race_test_;
106 // Separate thread for IO used by the HttpBridge.
107 base::Thread io_thread_;
108 base::MessageLoop loop_;
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(
122 new HttpBridge::RequestContextGetter(
123 baseline_context_getter, "user agent"),
124 NetworkTimeUpdateCallback()),
125 test_(test), never_finishes_(never_finishes) { }
126 protected:
127 virtual void MakeAsynchronousPost() OVERRIDE {
128 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
129 if (never_finishes_)
130 return;
132 // We don't actually want to make a request for this test, so just callback
133 // as if it completed.
134 test_->GetIOThreadLoop()->PostTask(FROM_HERE,
135 base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this));
137 private:
138 virtual ~ShuntedHttpBridge() {}
140 void CallOnURLFetchComplete() {
141 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
142 // We return no cookies and a dummy content response.
143 net::ResponseCookies cookies;
145 std::string response_content = "success!";
146 net::TestURLFetcher fetcher(0, GURL(), NULL);
147 fetcher.set_url(GURL("www.google.com"));
148 fetcher.set_response_code(200);
149 fetcher.set_cookies(cookies);
150 fetcher.SetResponseString(response_content);
151 OnURLFetchComplete(&fetcher);
153 SyncHttpBridgeTest* test_;
154 bool never_finishes_;
157 void SyncHttpBridgeTest::RunSyncThreadBridgeUseTest(
158 base::WaitableEvent* signal_when_created,
159 base::WaitableEvent* signal_when_released) {
160 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
161 new net::TestURLRequestContextGetter(io_thread_.message_loop_proxy()));
163 scoped_refptr<ShuntedHttpBridge> bridge(
164 new ShuntedHttpBridge(ctx_getter.get(), this, true));
165 bridge->SetURL("http://www.google.com", 9999);
166 bridge->SetPostPayload("text/plain", 2, " ");
167 bridge_for_race_test_ = bridge.get();
168 signal_when_created->Signal();
170 int os_error = 0;
171 int response_code = 0;
172 bridge->MakeSynchronousPost(&os_error, &response_code);
173 bridge_for_race_test_ = NULL;
175 signal_when_released->Signal();
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 io_thread()->message_loop()
182 ->PostTask(FROM_HERE,
183 base::Bind(&SyncHttpBridgeTest::TestSameHttpNetworkSession,
184 base::MessageLoop::current(),
185 this));
186 base::MessageLoop::current()->Run();
189 // Test the HttpBridge without actually making any network requests.
190 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostShunted) {
191 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
192 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
193 scoped_refptr<HttpBridge> http_bridge(
194 new ShuntedHttpBridge(ctx_getter.get(), this, false));
195 http_bridge->SetURL("http://www.google.com", 9999);
196 http_bridge->SetPostPayload("text/plain", 2, " ");
198 int os_error = 0;
199 int response_code = 0;
200 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
201 EXPECT_TRUE(success);
202 EXPECT_EQ(200, response_code);
203 EXPECT_EQ(0, os_error);
205 EXPECT_EQ(8, http_bridge->GetResponseContentLength());
206 EXPECT_EQ(std::string("success!"),
207 std::string(http_bridge->GetResponseContent()));
210 // Full round-trip test of the HttpBridge, using default UA string and
211 // no request cookies.
212 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
213 ASSERT_TRUE(test_server_.Start());
215 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
217 std::string payload = "this should be echoed back";
218 GURL echo = test_server_.GetURL("echo");
219 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
220 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
221 payload.length() + 1, payload.c_str());
222 int os_error = 0;
223 int response_code = 0;
224 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
225 EXPECT_TRUE(success);
226 EXPECT_EQ(200, response_code);
227 EXPECT_EQ(0, os_error);
229 EXPECT_EQ(payload.length() + 1,
230 static_cast<size_t>(http_bridge->GetResponseContentLength()));
231 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent()));
234 // Full round-trip test of the HttpBridge.
235 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
236 ASSERT_TRUE(test_server_.Start());
238 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
240 GURL echo_header = test_server_.GetURL("echoall");
241 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
243 std::string test_payload = "###TEST PAYLOAD###";
244 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
245 test_payload.c_str());
247 int os_error = 0;
248 int response_code = 0;
249 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
250 EXPECT_TRUE(success);
251 EXPECT_EQ(200, response_code);
252 EXPECT_EQ(0, os_error);
254 std::string response(http_bridge->GetResponseContent(),
255 http_bridge->GetResponseContentLength());
256 EXPECT_EQ(std::string::npos, response.find("Cookie:"));
257 EXPECT_NE(std::string::npos, response.find("User-Agent: user agent"));
258 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
261 TEST_F(SyncHttpBridgeTest, TestExtraRequestHeaders) {
262 ASSERT_TRUE(test_server_.Start());
264 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
266 GURL echo_header = test_server_.GetURL("echoall");
268 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
269 http_bridge->SetExtraRequestHeaders("test:fnord");
271 std::string test_payload = "###TEST PAYLOAD###";
272 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
273 test_payload.c_str());
275 int os_error = 0;
276 int response_code = 0;
277 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
278 EXPECT_TRUE(success);
279 EXPECT_EQ(200, response_code);
280 EXPECT_EQ(0, os_error);
282 std::string response(http_bridge->GetResponseContent(),
283 http_bridge->GetResponseContentLength());
285 EXPECT_NE(std::string::npos, response.find("fnord"));
286 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
289 TEST_F(SyncHttpBridgeTest, TestResponseHeader) {
290 ASSERT_TRUE(test_server_.Start());
292 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
294 GURL echo_header = test_server_.GetURL("echoall");
295 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
297 std::string test_payload = "###TEST PAYLOAD###";
298 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
299 test_payload.c_str());
301 int os_error = 0;
302 int response_code = 0;
303 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
304 EXPECT_TRUE(success);
305 EXPECT_EQ(200, response_code);
306 EXPECT_EQ(0, os_error);
308 EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html");
309 EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty());
312 TEST_F(SyncHttpBridgeTest, Abort) {
313 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
314 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
315 scoped_refptr<ShuntedHttpBridge> http_bridge(
316 new ShuntedHttpBridge(ctx_getter.get(), this, true));
317 http_bridge->SetURL("http://www.google.com", 9999);
318 http_bridge->SetPostPayload("text/plain", 2, " ");
320 int os_error = 0;
321 int response_code = 0;
323 io_thread()->message_loop_proxy()->PostTask(
324 FROM_HERE,
325 base::Bind(&SyncHttpBridgeTest::Abort, http_bridge));
326 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
327 EXPECT_FALSE(success);
328 EXPECT_EQ(net::ERR_ABORTED, os_error);
331 TEST_F(SyncHttpBridgeTest, AbortLate) {
332 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
333 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
334 scoped_refptr<ShuntedHttpBridge> http_bridge(
335 new ShuntedHttpBridge(ctx_getter.get(), this, false));
336 http_bridge->SetURL("http://www.google.com", 9999);
337 http_bridge->SetPostPayload("text/plain", 2, " ");
339 int os_error = 0;
340 int response_code = 0;
342 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
343 ASSERT_TRUE(success);
344 http_bridge->Abort();
345 // Ensures no double-free of URLFetcher, etc.
348 // Tests an interesting case where code using the HttpBridge aborts the fetch
349 // and releases ownership before a pending fetch completed callback is issued by
350 // the underlying URLFetcher (and before that URLFetcher is destroyed, which
351 // would cancel the callback).
352 TEST_F(SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) {
353 base::Thread sync_thread("SyncThread");
354 sync_thread.Start();
356 // First, block the sync thread on the post.
357 base::WaitableEvent signal_when_created(false, false);
358 base::WaitableEvent signal_when_released(false, false);
359 sync_thread.message_loop()->PostTask(FROM_HERE,
360 base::Bind(&SyncHttpBridgeTest::RunSyncThreadBridgeUseTest,
361 base::Unretained(this),
362 &signal_when_created,
363 &signal_when_released));
365 // Stop IO so we can control order of operations.
366 base::WaitableEvent io_waiter(false, false);
367 ASSERT_TRUE(io_thread()->message_loop_proxy()->PostTask(
368 FROM_HERE,
369 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter))));
371 signal_when_created.Wait(); // Wait till we have a bridge to abort.
372 ASSERT_TRUE(bridge_for_race_test());
374 // Schedule the fetch completion callback (but don't run it yet). Don't take
375 // a reference to the bridge to mimic URLFetcher's handling of the delegate.
376 net::URLFetcherDelegate* delegate =
377 static_cast<net::URLFetcherDelegate*>(bridge_for_race_test());
378 net::ResponseCookies cookies;
379 std::string response_content = "success!";
380 net::TestURLFetcher fetcher(0, GURL(), NULL);
381 fetcher.set_url(GURL("www.google.com"));
382 fetcher.set_response_code(200);
383 fetcher.set_cookies(cookies);
384 fetcher.SetResponseString(response_content);
385 ASSERT_TRUE(io_thread()->message_loop_proxy()->PostTask(
386 FROM_HERE,
387 base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete,
388 base::Unretained(delegate), &fetcher)));
390 // Abort the fetch. This should be smart enough to handle the case where
391 // the bridge is destroyed before the callback scheduled above completes.
392 bridge_for_race_test()->Abort();
394 // Wait until the sync thread releases its ref on the bridge.
395 signal_when_released.Wait();
396 ASSERT_FALSE(bridge_for_race_test());
398 // Unleash the hounds. The fetch completion callback should fire first, and
399 // succeed even though we Release()d the bridge above because the call to
400 // Abort should have held a reference.
401 io_waiter.Signal();
403 // Done.
404 sync_thread.Stop();
405 io_thread()->Stop();
408 void HttpBridgeRunOnSyncThread(
409 net::URLRequestContextGetter* baseline_context_getter,
410 CancelationSignal* factory_cancelation_signal,
411 syncer::HttpPostProviderFactory** bridge_factory_out,
412 syncer::HttpPostProviderInterface** bridge_out,
413 base::WaitableEvent* signal_when_created,
414 base::WaitableEvent* wait_for_shutdown) {
415 scoped_ptr<syncer::HttpBridgeFactory> bridge_factory(
416 new syncer::HttpBridgeFactory(baseline_context_getter,
417 NetworkTimeUpdateCallback(),
418 factory_cancelation_signal));
419 bridge_factory->Init("test");
420 *bridge_factory_out = bridge_factory.get();
422 HttpPostProviderInterface* bridge = bridge_factory->Create();
423 *bridge_out = bridge;
425 signal_when_created->Signal();
426 wait_for_shutdown->Wait();
428 bridge_factory->Destroy(bridge);
431 void WaitOnIOThread(base::WaitableEvent* signal_wait_start,
432 base::WaitableEvent* wait_done) {
433 signal_wait_start->Signal();
434 wait_done->Wait();
437 // Tests RequestContextGetter is properly released on IO thread even when
438 // IO thread stops before sync thread.
439 TEST_F(SyncHttpBridgeTest, RequestContextGetterReleaseOrder) {
440 base::Thread sync_thread("SyncThread");
441 sync_thread.Start();
443 syncer::HttpPostProviderFactory* factory = NULL;
444 syncer::HttpPostProviderInterface* bridge = NULL;
446 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
447 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
449 base::WaitableEvent signal_when_created(false, false);
450 base::WaitableEvent wait_for_shutdown(false, false);
452 CancelationSignal release_request_context_signal;
454 // Create bridge factory and factory on sync thread and wait for the creation
455 // to finish.
456 sync_thread.message_loop()->PostTask(FROM_HERE,
457 base::Bind(&HttpBridgeRunOnSyncThread,
458 base::Unretained(baseline_context_getter.get()),
459 &release_request_context_signal ,&factory, &bridge,
460 &signal_when_created, &wait_for_shutdown));
461 signal_when_created.Wait();
463 // Simulate sync shutdown by aborting bridge and shutting down factory on
464 // frontend.
465 bridge->Abort();
466 release_request_context_signal.Signal();
468 // Wait for sync's RequestContextGetter to be cleared on IO thread and
469 // check for reference count.
470 base::WaitableEvent signal_wait_start(false, false);
471 base::WaitableEvent wait_done(false, false);
472 io_thread()->message_loop()->PostTask(
473 FROM_HERE,
474 base::Bind(&WaitOnIOThread, &signal_wait_start, &wait_done));
475 signal_wait_start.Wait();
476 // |baseline_context_getter| should have only one reference from local
477 // variable.
478 EXPECT_TRUE(baseline_context_getter->HasOneRef());
479 baseline_context_getter = NULL;
481 // Unblock and stop IO thread before sync thread.
482 wait_done.Signal();
483 io_thread()->Stop();
485 // Unblock and stop sync thread.
486 wait_for_shutdown.Signal();
487 sync_thread.Stop();
490 // Attempt to release the URLRequestContextGetter before the HttpBridgeFactory
491 // is initialized.
492 TEST_F(SyncHttpBridgeTest, EarlyAbortFactory) {
493 // In a real scenario, the following would happen on many threads. For
494 // simplicity, this test uses only one thread.
496 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
497 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
498 CancelationSignal release_request_context_signal;
500 // UI Thread: Initialize the HttpBridgeFactory. The next step would be to
501 // post a task to SBH::Core to have it initialized.
502 scoped_ptr<syncer::HttpBridgeFactory> factory(
503 new HttpBridgeFactory(baseline_context_getter.get(),
504 NetworkTimeUpdateCallback(),
505 &release_request_context_signal));
507 // UI Thread: A very early shutdown request arrives and executes on the UI
508 // thread before the posted sync thread task is run.
509 release_request_context_signal.Signal();
511 // Sync thread: Finally run the posted task, only to find that our
512 // HttpBridgeFactory has been neutered. Should not crash.
513 factory->Init("TestUserAgent");
515 // At this point, attempting to use the factory would trigger a crash. Both
516 // this test and the real world code should make sure this never happens.
519 } // namespace syncer