Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / sync / internal_api / http_bridge_unittest.cc
blob4ea4e705d749d67d88d7bd4c2916c283aebce657
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/metrics/field_trial.h"
6 #include "base/strings/stringprintf.h"
7 #include "base/synchronization/waitable_event.h"
8 #include "base/test/mock_entropy_provider.h"
9 #include "base/threading/thread.h"
10 #include "net/http/http_response_headers.h"
11 #include "net/test/spawned_test_server/spawned_test_server.h"
12 #include "net/url_request/test_url_fetcher_factory.h"
13 #include "net/url_request/url_fetcher_delegate.h"
14 #include "net/url_request/url_request_test_util.h"
15 #include "sync/internal_api/public/base/cancelation_signal.h"
16 #include "sync/internal_api/public/http_bridge.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/zlib/zlib.h"
20 namespace syncer {
22 namespace {
24 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113.
25 const base::FilePath::CharType kDocRoot[] =
26 FILE_PATH_LITERAL("chrome/test/data");
28 // -----------------------------------------------------------------------------
29 // The rest of the code in the anon namespace is copied from
30 // components/compression/compression_utils.cc
31 // TODO(gangwu): crbug.com/515695. The following codes are copied from
32 // components/compression/compression_utils.cc, we copied them because if we
33 // reference them, we will get cycle dependency warning. Once the functions
34 // have been moved from //component to //base, we can remove the following
35 // functions.
36 //------------------------------------------------------------------------------
37 // Pass an integer greater than the following get a gzip header instead of a
38 // zlib header when calling deflateInit2() and inflateInit2().
39 const int kWindowBitsToGetGzipHeader = 16;
41 // This code is taken almost verbatim from third_party/zlib/uncompr.c. The only
42 // difference is inflateInit2() is called which sets the window bits to be > 16.
43 // That causes a gzip header to be parsed rather than a zlib header.
44 int GzipUncompressHelper(Bytef* dest,
45 uLongf* dest_length,
46 const Bytef* source,
47 uLong source_length) {
48 z_stream stream;
50 stream.next_in = bit_cast<Bytef*>(source);
51 stream.avail_in = static_cast<uInt>(source_length);
52 if (static_cast<uLong>(stream.avail_in) != source_length)
53 return Z_BUF_ERROR;
55 stream.next_out = dest;
56 stream.avail_out = static_cast<uInt>(*dest_length);
57 if (static_cast<uLong>(stream.avail_out) != *dest_length)
58 return Z_BUF_ERROR;
60 stream.zalloc = static_cast<alloc_func>(0);
61 stream.zfree = static_cast<free_func>(0);
63 int err = inflateInit2(&stream, MAX_WBITS + kWindowBitsToGetGzipHeader);
64 if (err != Z_OK)
65 return err;
67 err = inflate(&stream, Z_FINISH);
68 if (err != Z_STREAM_END) {
69 inflateEnd(&stream);
70 if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
71 return Z_DATA_ERROR;
72 return err;
74 *dest_length = stream.total_out;
76 err = inflateEnd(&stream);
77 return err;
80 // Returns the uncompressed size from GZIP-compressed |compressed_data|.
81 uint32 GetUncompressedSize(const std::string& compressed_data) {
82 // The uncompressed size is stored in the last 4 bytes of |input| in LE.
83 uint32 size;
84 if (compressed_data.length() < sizeof(size))
85 return 0;
86 memcpy(&size, &compressed_data[compressed_data.length() - sizeof(size)],
87 sizeof(size));
88 return base::ByteSwapToLE32(size);
91 bool GzipUncompress(const std::string& input, std::string* output) {
92 std::string uncompressed_output;
93 uLongf uncompressed_size = static_cast<uLongf>(GetUncompressedSize(input));
94 uncompressed_output.resize(uncompressed_size);
95 if (GzipUncompressHelper(bit_cast<Bytef*>(uncompressed_output.data()),
96 &uncompressed_size,
97 bit_cast<const Bytef*>(input.data()),
98 static_cast<uLongf>(input.length())) == Z_OK) {
99 output->swap(uncompressed_output);
100 return true;
102 return false;
105 } // namespace
107 const char kUserAgent[] = "user-agent";
109 #if defined(OS_ANDROID)
110 #define MAYBE_SyncHttpBridgeTest DISABLED_SyncHttpBridgeTest
111 #else
112 #define MAYBE_SyncHttpBridgeTest SyncHttpBridgeTest
113 #endif // defined(OS_ANDROID)
114 class MAYBE_SyncHttpBridgeTest : public testing::Test {
115 public:
116 MAYBE_SyncHttpBridgeTest()
117 : test_server_(net::SpawnedTestServer::TYPE_HTTP,
118 net::SpawnedTestServer::kLocalhost,
119 base::FilePath(kDocRoot)),
120 fake_default_request_context_getter_(NULL),
121 bridge_for_race_test_(NULL),
122 io_thread_("IO thread") {
125 void SetUp() override {
126 base::Thread::Options options;
127 options.message_loop_type = base::MessageLoop::TYPE_IO;
128 io_thread_.StartWithOptions(options);
131 void TearDown() override {
132 if (fake_default_request_context_getter_) {
133 GetIOThreadLoop()->ReleaseSoon(FROM_HERE,
134 fake_default_request_context_getter_);
135 fake_default_request_context_getter_ = NULL;
137 io_thread_.Stop();
140 HttpBridge* BuildBridge() {
141 if (!fake_default_request_context_getter_) {
142 fake_default_request_context_getter_ =
143 new net::TestURLRequestContextGetter(io_thread_.task_runner());
144 fake_default_request_context_getter_->AddRef();
146 HttpBridge* bridge =
147 new HttpBridge(kUserAgent,
148 fake_default_request_context_getter_,
149 NetworkTimeUpdateCallback());
150 return bridge;
153 static void Abort(HttpBridge* bridge) {
154 bridge->Abort();
157 // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race
158 // condition.
159 void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created,
160 base::WaitableEvent* signal_when_released);
162 static void TestSameHttpNetworkSession(base::MessageLoop* main_message_loop,
163 MAYBE_SyncHttpBridgeTest* test) {
164 scoped_refptr<HttpBridge> http_bridge(test->BuildBridge());
165 EXPECT_TRUE(test->GetTestRequestContextGetter());
166 net::HttpNetworkSession* test_session =
167 test->GetTestRequestContextGetter()->GetURLRequestContext()->
168 http_transaction_factory()->GetSession();
169 EXPECT_EQ(test_session,
170 http_bridge->GetRequestContextGetterForTest()->
171 GetURLRequestContext()->
172 http_transaction_factory()->GetSession());
173 main_message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
176 base::MessageLoop* GetIOThreadLoop() { return io_thread_.message_loop(); }
178 // Note this is lazy created, so don't call this before your bridge.
179 net::TestURLRequestContextGetter* GetTestRequestContextGetter() {
180 return fake_default_request_context_getter_;
183 net::SpawnedTestServer test_server_;
185 base::Thread* io_thread() { return &io_thread_; }
187 HttpBridge* bridge_for_race_test() { return bridge_for_race_test_; }
189 private:
190 // A make-believe "default" request context, as would be returned by
191 // Profile::GetDefaultRequestContext(). Created lazily by BuildBridge.
192 net::TestURLRequestContextGetter* fake_default_request_context_getter_;
194 HttpBridge* bridge_for_race_test_;
196 // Separate thread for IO used by the HttpBridge.
197 base::Thread io_thread_;
198 base::MessageLoop loop_;
201 // An HttpBridge that doesn't actually make network requests and just calls
202 // back with dummy response info.
203 // TODO(tim): Instead of inheriting here we should inject a component
204 // responsible for the MakeAsynchronousPost bit.
205 class ShuntedHttpBridge : public HttpBridge {
206 public:
207 // If |never_finishes| is true, the simulated request never actually
208 // returns.
209 ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter,
210 MAYBE_SyncHttpBridgeTest* test, bool never_finishes)
211 : HttpBridge(kUserAgent,
212 baseline_context_getter,
213 NetworkTimeUpdateCallback()),
214 test_(test), never_finishes_(never_finishes) { }
215 protected:
216 void MakeAsynchronousPost() override {
217 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
218 if (never_finishes_)
219 return;
221 // We don't actually want to make a request for this test, so just callback
222 // as if it completed.
223 test_->GetIOThreadLoop()->PostTask(FROM_HERE,
224 base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this));
226 private:
227 ~ShuntedHttpBridge() override {}
229 void CallOnURLFetchComplete() {
230 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
231 // We return no cookies and a dummy content response.
232 net::ResponseCookies cookies;
234 std::string response_content = "success!";
235 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL);
236 scoped_refptr<net::HttpResponseHeaders> response_headers(
237 new net::HttpResponseHeaders(""));
238 fetcher.set_response_code(200);
239 fetcher.set_cookies(cookies);
240 fetcher.SetResponseString(response_content);
241 fetcher.set_response_headers(response_headers);
242 OnURLFetchComplete(&fetcher);
244 MAYBE_SyncHttpBridgeTest* test_;
245 bool never_finishes_;
248 void MAYBE_SyncHttpBridgeTest::RunSyncThreadBridgeUseTest(
249 base::WaitableEvent* signal_when_created,
250 base::WaitableEvent* signal_when_released) {
251 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
252 new net::TestURLRequestContextGetter(io_thread_.task_runner()));
254 scoped_refptr<ShuntedHttpBridge> bridge(
255 new ShuntedHttpBridge(ctx_getter.get(), this, true));
256 bridge->SetURL("http://www.google.com", 9999);
257 bridge->SetPostPayload("text/plain", 2, " ");
258 bridge_for_race_test_ = bridge.get();
259 signal_when_created->Signal();
261 int os_error = 0;
262 int response_code = 0;
263 bridge->MakeSynchronousPost(&os_error, &response_code);
264 bridge_for_race_test_ = NULL;
266 signal_when_released->Signal();
269 TEST_F(MAYBE_SyncHttpBridgeTest, TestUsesSameHttpNetworkSession) {
270 // Run this test on the IO thread because we can only call
271 // URLRequestContextGetter::GetURLRequestContext on the IO thread.
272 io_thread()->message_loop()->PostTask(
273 FROM_HERE,
274 base::Bind(&MAYBE_SyncHttpBridgeTest::TestSameHttpNetworkSession,
275 base::MessageLoop::current(), this));
276 base::MessageLoop::current()->Run();
279 // Test the HttpBridge without actually making any network requests.
280 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostShunted) {
281 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
282 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
283 scoped_refptr<HttpBridge> http_bridge(
284 new ShuntedHttpBridge(ctx_getter.get(), this, false));
285 http_bridge->SetURL("http://www.google.com", 9999);
286 http_bridge->SetPostPayload("text/plain", 2, " ");
288 int os_error = 0;
289 int response_code = 0;
290 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
291 EXPECT_TRUE(success);
292 EXPECT_EQ(200, response_code);
293 EXPECT_EQ(0, os_error);
295 EXPECT_EQ(8, http_bridge->GetResponseContentLength());
296 EXPECT_EQ(std::string("success!"),
297 std::string(http_bridge->GetResponseContent()));
300 // Full round-trip test of the HttpBridge, using default UA string and
301 // no request cookies.
302 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
303 ASSERT_TRUE(test_server_.Start());
305 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
307 std::string payload = "this should be echoed back";
308 GURL echo = test_server_.GetURL("echo");
309 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
310 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
311 payload.length() + 1, payload.c_str());
312 int os_error = 0;
313 int response_code = 0;
314 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
315 EXPECT_TRUE(success);
316 EXPECT_EQ(200, response_code);
317 EXPECT_EQ(0, os_error);
319 EXPECT_EQ(payload.length() + 1,
320 static_cast<size_t>(http_bridge->GetResponseContentLength()));
321 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent()));
324 // Full round-trip test of the HttpBridge with compressed data, check if the
325 // data is correctly compressed.
326 TEST_F(MAYBE_SyncHttpBridgeTest, CompressedRequestPayloadCheck) {
327 ASSERT_TRUE(test_server_.Start());
329 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
331 std::string payload = "this should be echoed back";
332 GURL echo = test_server_.GetURL("echo");
333 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
334 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
335 payload.length(), payload.c_str());
336 int os_error = 0;
337 int response_code = 0;
338 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
339 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression",
340 "Enabled");
341 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
342 EXPECT_TRUE(success);
343 EXPECT_EQ(200, response_code);
344 EXPECT_EQ(0, os_error);
346 EXPECT_NE(payload.length() + 1,
347 static_cast<size_t>(http_bridge->GetResponseContentLength()));
348 std::string compressed_payload(http_bridge->GetResponseContent(),
349 http_bridge->GetResponseContentLength());
350 std::string uncompressed_payload;
351 GzipUncompress(compressed_payload, &uncompressed_payload);
352 EXPECT_EQ(payload, uncompressed_payload);
355 // Full round-trip test of the HttpBridge with compression, check if header
356 // fields("Content-Encoding" ,"Accept-Encoding" and user agent) are set
357 // correctly.
358 TEST_F(MAYBE_SyncHttpBridgeTest, CompressedRequestHeaderCheck) {
359 ASSERT_TRUE(test_server_.Start());
361 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
363 GURL echo_header = test_server_.GetURL("echoall");
364 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
366 std::string test_payload = "###TEST PAYLOAD###";
367 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
368 test_payload.c_str());
370 int os_error = 0;
371 int response_code = 0;
372 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
373 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression",
374 "Enabled");
375 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
376 EXPECT_TRUE(success);
377 EXPECT_EQ(200, response_code);
378 EXPECT_EQ(0, os_error);
380 std::string response(http_bridge->GetResponseContent(),
381 http_bridge->GetResponseContentLength());
382 EXPECT_NE(std::string::npos, response.find("Content-Encoding: gzip"));
383 EXPECT_NE(std::string::npos,
384 response.find(base::StringPrintf(
385 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding,
386 "gzip, deflate")));
387 EXPECT_NE(std::string::npos,
388 response.find(base::StringPrintf(
389 "%s: %s", net::HttpRequestHeaders::kUserAgent, kUserAgent)));
392 // Full round-trip test of the HttpBridge.
393 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
394 ASSERT_TRUE(test_server_.Start());
396 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
398 GURL echo_header = test_server_.GetURL("echoall");
399 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
401 std::string test_payload = "###TEST PAYLOAD###";
402 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
403 test_payload.c_str());
405 int os_error = 0;
406 int response_code = 0;
407 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
408 EXPECT_TRUE(success);
409 EXPECT_EQ(200, response_code);
410 EXPECT_EQ(0, os_error);
412 std::string response(http_bridge->GetResponseContent(),
413 http_bridge->GetResponseContentLength());
414 EXPECT_EQ(std::string::npos, response.find("Cookie:"));
415 EXPECT_NE(std::string::npos,
416 response.find(base::StringPrintf(
417 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding,
418 "deflate")));
419 EXPECT_NE(std::string::npos,
420 response.find(base::StringPrintf("%s: %s",
421 net::HttpRequestHeaders::kUserAgent, kUserAgent)));
422 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
425 TEST_F(MAYBE_SyncHttpBridgeTest, TestExtraRequestHeaders) {
426 ASSERT_TRUE(test_server_.Start());
428 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
430 GURL echo_header = test_server_.GetURL("echoall");
432 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
433 http_bridge->SetExtraRequestHeaders("test:fnord");
435 std::string test_payload = "###TEST PAYLOAD###";
436 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
437 test_payload.c_str());
439 int os_error = 0;
440 int response_code = 0;
441 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
442 EXPECT_TRUE(success);
443 EXPECT_EQ(200, response_code);
444 EXPECT_EQ(0, os_error);
446 std::string response(http_bridge->GetResponseContent(),
447 http_bridge->GetResponseContentLength());
449 EXPECT_NE(std::string::npos, response.find("fnord"));
450 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
453 TEST_F(MAYBE_SyncHttpBridgeTest, TestResponseHeader) {
454 ASSERT_TRUE(test_server_.Start());
456 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
458 GURL echo_header = test_server_.GetURL("echoall");
459 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
461 std::string test_payload = "###TEST PAYLOAD###";
462 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
463 test_payload.c_str());
465 int os_error = 0;
466 int response_code = 0;
467 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
468 EXPECT_TRUE(success);
469 EXPECT_EQ(200, response_code);
470 EXPECT_EQ(0, os_error);
472 EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html");
473 EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty());
476 TEST_F(MAYBE_SyncHttpBridgeTest, Abort) {
477 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
478 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
479 scoped_refptr<ShuntedHttpBridge> http_bridge(
480 new ShuntedHttpBridge(ctx_getter.get(), this, true));
481 http_bridge->SetURL("http://www.google.com", 9999);
482 http_bridge->SetPostPayload("text/plain", 2, " ");
484 int os_error = 0;
485 int response_code = 0;
487 io_thread()->task_runner()->PostTask(
488 FROM_HERE,
489 base::Bind(&MAYBE_SyncHttpBridgeTest::Abort, http_bridge));
490 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
491 EXPECT_FALSE(success);
492 EXPECT_EQ(net::ERR_ABORTED, os_error);
495 TEST_F(MAYBE_SyncHttpBridgeTest, AbortLate) {
496 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
497 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
498 scoped_refptr<ShuntedHttpBridge> http_bridge(
499 new ShuntedHttpBridge(ctx_getter.get(), this, false));
500 http_bridge->SetURL("http://www.google.com", 9999);
501 http_bridge->SetPostPayload("text/plain", 2, " ");
503 int os_error = 0;
504 int response_code = 0;
506 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
507 ASSERT_TRUE(success);
508 http_bridge->Abort();
509 // Ensures no double-free of URLFetcher, etc.
512 // Tests an interesting case where code using the HttpBridge aborts the fetch
513 // and releases ownership before a pending fetch completed callback is issued by
514 // the underlying URLFetcher (and before that URLFetcher is destroyed, which
515 // would cancel the callback).
516 TEST_F(MAYBE_SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) {
517 base::Thread sync_thread("SyncThread");
518 sync_thread.Start();
520 // First, block the sync thread on the post.
521 base::WaitableEvent signal_when_created(false, false);
522 base::WaitableEvent signal_when_released(false, false);
523 sync_thread.message_loop()->PostTask(FROM_HERE,
524 base::Bind(&MAYBE_SyncHttpBridgeTest::RunSyncThreadBridgeUseTest,
525 base::Unretained(this),
526 &signal_when_created,
527 &signal_when_released));
529 // Stop IO so we can control order of operations.
530 base::WaitableEvent io_waiter(false, false);
531 ASSERT_TRUE(io_thread()->task_runner()->PostTask(
532 FROM_HERE,
533 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter))));
535 signal_when_created.Wait(); // Wait till we have a bridge to abort.
536 ASSERT_TRUE(bridge_for_race_test());
538 // Schedule the fetch completion callback (but don't run it yet). Don't take
539 // a reference to the bridge to mimic URLFetcher's handling of the delegate.
540 net::URLFetcherDelegate* delegate =
541 static_cast<net::URLFetcherDelegate*>(bridge_for_race_test());
542 net::ResponseCookies cookies;
543 std::string response_content = "success!";
544 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL);
545 fetcher.set_response_code(200);
546 fetcher.set_cookies(cookies);
547 fetcher.SetResponseString(response_content);
548 ASSERT_TRUE(io_thread()->task_runner()->PostTask(
549 FROM_HERE,
550 base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete,
551 base::Unretained(delegate), &fetcher)));
553 // Abort the fetch. This should be smart enough to handle the case where
554 // the bridge is destroyed before the callback scheduled above completes.
555 bridge_for_race_test()->Abort();
557 // Wait until the sync thread releases its ref on the bridge.
558 signal_when_released.Wait();
559 ASSERT_FALSE(bridge_for_race_test());
561 // Unleash the hounds. The fetch completion callback should fire first, and
562 // succeed even though we Release()d the bridge above because the call to
563 // Abort should have held a reference.
564 io_waiter.Signal();
566 // Done.
567 sync_thread.Stop();
568 io_thread()->Stop();
571 void HttpBridgeRunOnSyncThread(
572 net::URLRequestContextGetter* baseline_context_getter,
573 CancelationSignal* factory_cancelation_signal,
574 syncer::HttpPostProviderFactory** bridge_factory_out,
575 syncer::HttpPostProviderInterface** bridge_out,
576 base::WaitableEvent* signal_when_created,
577 base::WaitableEvent* wait_for_shutdown) {
578 scoped_ptr<syncer::HttpBridgeFactory> bridge_factory(
579 new syncer::HttpBridgeFactory(baseline_context_getter,
580 NetworkTimeUpdateCallback(),
581 factory_cancelation_signal));
582 bridge_factory->Init("test");
583 *bridge_factory_out = bridge_factory.get();
585 HttpPostProviderInterface* bridge = bridge_factory->Create();
586 *bridge_out = bridge;
588 signal_when_created->Signal();
589 wait_for_shutdown->Wait();
591 bridge_factory->Destroy(bridge);
594 void WaitOnIOThread(base::WaitableEvent* signal_wait_start,
595 base::WaitableEvent* wait_done) {
596 signal_wait_start->Signal();
597 wait_done->Wait();
600 // Tests RequestContextGetter is properly released on IO thread even when
601 // IO thread stops before sync thread.
602 TEST_F(MAYBE_SyncHttpBridgeTest, RequestContextGetterReleaseOrder) {
603 base::Thread sync_thread("SyncThread");
604 sync_thread.Start();
606 syncer::HttpPostProviderFactory* factory = NULL;
607 syncer::HttpPostProviderInterface* bridge = NULL;
609 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
610 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
612 base::WaitableEvent signal_when_created(false, false);
613 base::WaitableEvent wait_for_shutdown(false, false);
615 CancelationSignal release_request_context_signal;
617 // Create bridge factory and factory on sync thread and wait for the creation
618 // to finish.
619 sync_thread.message_loop()->PostTask(FROM_HERE,
620 base::Bind(&HttpBridgeRunOnSyncThread,
621 base::Unretained(baseline_context_getter.get()),
622 &release_request_context_signal ,&factory, &bridge,
623 &signal_when_created, &wait_for_shutdown));
624 signal_when_created.Wait();
626 // Simulate sync shutdown by aborting bridge and shutting down factory on
627 // frontend.
628 bridge->Abort();
629 release_request_context_signal.Signal();
631 // Wait for sync's RequestContextGetter to be cleared on IO thread and
632 // check for reference count.
633 base::WaitableEvent signal_wait_start(false, false);
634 base::WaitableEvent wait_done(false, false);
635 io_thread()->message_loop()->PostTask(
636 FROM_HERE,
637 base::Bind(&WaitOnIOThread, &signal_wait_start, &wait_done));
638 signal_wait_start.Wait();
639 // |baseline_context_getter| should have only one reference from local
640 // variable.
641 EXPECT_TRUE(baseline_context_getter->HasOneRef());
642 baseline_context_getter = NULL;
644 // Unblock and stop IO thread before sync thread.
645 wait_done.Signal();
646 io_thread()->Stop();
648 // Unblock and stop sync thread.
649 wait_for_shutdown.Signal();
650 sync_thread.Stop();
653 // Attempt to release the URLRequestContextGetter before the HttpBridgeFactory
654 // is initialized.
655 TEST_F(MAYBE_SyncHttpBridgeTest, EarlyAbortFactory) {
656 // In a real scenario, the following would happen on many threads. For
657 // simplicity, this test uses only one thread.
659 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
660 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
661 CancelationSignal release_request_context_signal;
663 // UI Thread: Initialize the HttpBridgeFactory. The next step would be to
664 // post a task to SBH::Core to have it initialized.
665 scoped_ptr<syncer::HttpBridgeFactory> factory(
666 new HttpBridgeFactory(baseline_context_getter.get(),
667 NetworkTimeUpdateCallback(),
668 &release_request_context_signal));
670 // UI Thread: A very early shutdown request arrives and executes on the UI
671 // thread before the posted sync thread task is run.
672 release_request_context_signal.Signal();
674 // Sync thread: Finally run the posted task, only to find that our
675 // HttpBridgeFactory has been neutered. Should not crash.
676 factory->Init("TestUserAgent");
678 // At this point, attempting to use the factory would trigger a crash. Both
679 // this test and the real world code should make sure this never happens.
682 } // namespace syncer