Add ICU message format support
[chromium-blink-merge.git] / sync / internal_api / http_bridge_unittest.cc
blobd1cc9140e0a2303346f71ceae257306818529701
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/metrics/compression_utils.cc
31 // TODO(gangwu): crbug.com/515695. The following codes are copied from
32 // components/metrics/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 class SyncHttpBridgeTest : public testing::Test {
110 public:
111 SyncHttpBridgeTest()
112 : test_server_(net::SpawnedTestServer::TYPE_HTTP,
113 net::SpawnedTestServer::kLocalhost,
114 base::FilePath(kDocRoot)),
115 fake_default_request_context_getter_(NULL),
116 bridge_for_race_test_(NULL),
117 io_thread_("IO thread") {
120 void SetUp() override {
121 base::Thread::Options options;
122 options.message_loop_type = base::MessageLoop::TYPE_IO;
123 io_thread_.StartWithOptions(options);
126 void TearDown() override {
127 if (fake_default_request_context_getter_) {
128 GetIOThreadLoop()->ReleaseSoon(FROM_HERE,
129 fake_default_request_context_getter_);
130 fake_default_request_context_getter_ = NULL;
132 io_thread_.Stop();
135 HttpBridge* BuildBridge() {
136 if (!fake_default_request_context_getter_) {
137 fake_default_request_context_getter_ =
138 new net::TestURLRequestContextGetter(io_thread_.task_runner());
139 fake_default_request_context_getter_->AddRef();
141 HttpBridge* bridge =
142 new HttpBridge(kUserAgent,
143 fake_default_request_context_getter_,
144 NetworkTimeUpdateCallback());
145 return bridge;
148 static void Abort(HttpBridge* bridge) {
149 bridge->Abort();
152 // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race
153 // condition.
154 void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created,
155 base::WaitableEvent* signal_when_released);
157 static void TestSameHttpNetworkSession(base::MessageLoop* main_message_loop,
158 SyncHttpBridgeTest* test) {
159 scoped_refptr<HttpBridge> http_bridge(test->BuildBridge());
160 EXPECT_TRUE(test->GetTestRequestContextGetter());
161 net::HttpNetworkSession* test_session =
162 test->GetTestRequestContextGetter()->GetURLRequestContext()->
163 http_transaction_factory()->GetSession();
164 EXPECT_EQ(test_session,
165 http_bridge->GetRequestContextGetterForTest()->
166 GetURLRequestContext()->
167 http_transaction_factory()->GetSession());
168 main_message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
171 base::MessageLoop* GetIOThreadLoop() { return io_thread_.message_loop(); }
173 // Note this is lazy created, so don't call this before your bridge.
174 net::TestURLRequestContextGetter* GetTestRequestContextGetter() {
175 return fake_default_request_context_getter_;
178 net::SpawnedTestServer test_server_;
180 base::Thread* io_thread() { return &io_thread_; }
182 HttpBridge* bridge_for_race_test() { return bridge_for_race_test_; }
184 private:
185 // A make-believe "default" request context, as would be returned by
186 // Profile::GetDefaultRequestContext(). Created lazily by BuildBridge.
187 net::TestURLRequestContextGetter* fake_default_request_context_getter_;
189 HttpBridge* bridge_for_race_test_;
191 // Separate thread for IO used by the HttpBridge.
192 base::Thread io_thread_;
193 base::MessageLoop loop_;
196 // An HttpBridge that doesn't actually make network requests and just calls
197 // back with dummy response info.
198 // TODO(tim): Instead of inheriting here we should inject a component
199 // responsible for the MakeAsynchronousPost bit.
200 class ShuntedHttpBridge : public HttpBridge {
201 public:
202 // If |never_finishes| is true, the simulated request never actually
203 // returns.
204 ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter,
205 SyncHttpBridgeTest* test, bool never_finishes)
206 : HttpBridge(kUserAgent,
207 baseline_context_getter,
208 NetworkTimeUpdateCallback()),
209 test_(test), never_finishes_(never_finishes) { }
210 protected:
211 void MakeAsynchronousPost() override {
212 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
213 if (never_finishes_)
214 return;
216 // We don't actually want to make a request for this test, so just callback
217 // as if it completed.
218 test_->GetIOThreadLoop()->PostTask(FROM_HERE,
219 base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this));
221 private:
222 ~ShuntedHttpBridge() override {}
224 void CallOnURLFetchComplete() {
225 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
226 // We return no cookies and a dummy content response.
227 net::ResponseCookies cookies;
229 std::string response_content = "success!";
230 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL);
231 scoped_refptr<net::HttpResponseHeaders> response_headers(
232 new net::HttpResponseHeaders(""));
233 fetcher.set_response_code(200);
234 fetcher.set_cookies(cookies);
235 fetcher.SetResponseString(response_content);
236 fetcher.set_response_headers(response_headers);
237 OnURLFetchComplete(&fetcher);
239 SyncHttpBridgeTest* test_;
240 bool never_finishes_;
243 void SyncHttpBridgeTest::RunSyncThreadBridgeUseTest(
244 base::WaitableEvent* signal_when_created,
245 base::WaitableEvent* signal_when_released) {
246 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
247 new net::TestURLRequestContextGetter(io_thread_.task_runner()));
249 scoped_refptr<ShuntedHttpBridge> bridge(
250 new ShuntedHttpBridge(ctx_getter.get(), this, true));
251 bridge->SetURL("http://www.google.com", 9999);
252 bridge->SetPostPayload("text/plain", 2, " ");
253 bridge_for_race_test_ = bridge.get();
254 signal_when_created->Signal();
256 int os_error = 0;
257 int response_code = 0;
258 bridge->MakeSynchronousPost(&os_error, &response_code);
259 bridge_for_race_test_ = NULL;
261 signal_when_released->Signal();
264 TEST_F(SyncHttpBridgeTest, TestUsesSameHttpNetworkSession) {
265 // Run this test on the IO thread because we can only call
266 // URLRequestContextGetter::GetURLRequestContext on the IO thread.
267 io_thread()->message_loop()
268 ->PostTask(FROM_HERE,
269 base::Bind(&SyncHttpBridgeTest::TestSameHttpNetworkSession,
270 base::MessageLoop::current(),
271 this));
272 base::MessageLoop::current()->Run();
275 // Test the HttpBridge without actually making any network requests.
276 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostShunted) {
277 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
278 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
279 scoped_refptr<HttpBridge> http_bridge(
280 new ShuntedHttpBridge(ctx_getter.get(), this, false));
281 http_bridge->SetURL("http://www.google.com", 9999);
282 http_bridge->SetPostPayload("text/plain", 2, " ");
284 int os_error = 0;
285 int response_code = 0;
286 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
287 EXPECT_TRUE(success);
288 EXPECT_EQ(200, response_code);
289 EXPECT_EQ(0, os_error);
291 EXPECT_EQ(8, http_bridge->GetResponseContentLength());
292 EXPECT_EQ(std::string("success!"),
293 std::string(http_bridge->GetResponseContent()));
296 // Full round-trip test of the HttpBridge, using default UA string and
297 // no request cookies.
298 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
299 ASSERT_TRUE(test_server_.Start());
301 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
303 std::string payload = "this should be echoed back";
304 GURL echo = test_server_.GetURL("echo");
305 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
306 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
307 payload.length() + 1, payload.c_str());
308 int os_error = 0;
309 int response_code = 0;
310 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
311 EXPECT_TRUE(success);
312 EXPECT_EQ(200, response_code);
313 EXPECT_EQ(0, os_error);
315 EXPECT_EQ(payload.length() + 1,
316 static_cast<size_t>(http_bridge->GetResponseContentLength()));
317 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent()));
320 // Full round-trip test of the HttpBridge with compressed data, check if the
321 // data is correctly compressed.
322 TEST_F(SyncHttpBridgeTest, CompressedRequestPayloadCheck) {
323 ASSERT_TRUE(test_server_.Start());
325 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
327 std::string payload = "this should be echoed back";
328 GURL echo = test_server_.GetURL("echo");
329 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
330 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
331 payload.length(), payload.c_str());
332 int os_error = 0;
333 int response_code = 0;
334 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
335 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression",
336 "Enabled");
337 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
338 EXPECT_TRUE(success);
339 EXPECT_EQ(200, response_code);
340 EXPECT_EQ(0, os_error);
342 EXPECT_NE(payload.length() + 1,
343 static_cast<size_t>(http_bridge->GetResponseContentLength()));
344 std::string compressed_payload(http_bridge->GetResponseContent(),
345 http_bridge->GetResponseContentLength());
346 std::string uncompressed_payload;
347 GzipUncompress(compressed_payload, &uncompressed_payload);
348 EXPECT_EQ(payload, uncompressed_payload);
351 // Full round-trip test of the HttpBridge with compression, check if header
352 // fields("Content-Encoding" ,"Accept-Encoding" and user agent) are set
353 // correctly.
354 TEST_F(SyncHttpBridgeTest, CompressedRequestHeaderCheck) {
355 ASSERT_TRUE(test_server_.Start());
357 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
359 GURL echo_header = test_server_.GetURL("echoall");
360 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
362 std::string test_payload = "###TEST PAYLOAD###";
363 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
364 test_payload.c_str());
366 int os_error = 0;
367 int response_code = 0;
368 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
369 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression",
370 "Enabled");
371 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
372 EXPECT_TRUE(success);
373 EXPECT_EQ(200, response_code);
374 EXPECT_EQ(0, os_error);
376 std::string response(http_bridge->GetResponseContent(),
377 http_bridge->GetResponseContentLength());
378 EXPECT_NE(std::string::npos, response.find("Content-Encoding: gzip"));
379 EXPECT_NE(std::string::npos,
380 response.find(base::StringPrintf(
381 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding,
382 "gzip, deflate")));
383 EXPECT_NE(std::string::npos,
384 response.find(base::StringPrintf(
385 "%s: %s", net::HttpRequestHeaders::kUserAgent, kUserAgent)));
388 // Full round-trip test of the HttpBridge.
389 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
390 ASSERT_TRUE(test_server_.Start());
392 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
394 GURL echo_header = test_server_.GetURL("echoall");
395 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
397 std::string test_payload = "###TEST PAYLOAD###";
398 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
399 test_payload.c_str());
401 int os_error = 0;
402 int response_code = 0;
403 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
404 EXPECT_TRUE(success);
405 EXPECT_EQ(200, response_code);
406 EXPECT_EQ(0, os_error);
408 std::string response(http_bridge->GetResponseContent(),
409 http_bridge->GetResponseContentLength());
410 EXPECT_EQ(std::string::npos, response.find("Cookie:"));
411 EXPECT_NE(std::string::npos,
412 response.find(base::StringPrintf(
413 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding,
414 "deflate")));
415 EXPECT_NE(std::string::npos,
416 response.find(base::StringPrintf("%s: %s",
417 net::HttpRequestHeaders::kUserAgent, kUserAgent)));
418 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
421 TEST_F(SyncHttpBridgeTest, TestExtraRequestHeaders) {
422 ASSERT_TRUE(test_server_.Start());
424 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
426 GURL echo_header = test_server_.GetURL("echoall");
428 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
429 http_bridge->SetExtraRequestHeaders("test:fnord");
431 std::string test_payload = "###TEST PAYLOAD###";
432 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
433 test_payload.c_str());
435 int os_error = 0;
436 int response_code = 0;
437 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
438 EXPECT_TRUE(success);
439 EXPECT_EQ(200, response_code);
440 EXPECT_EQ(0, os_error);
442 std::string response(http_bridge->GetResponseContent(),
443 http_bridge->GetResponseContentLength());
445 EXPECT_NE(std::string::npos, response.find("fnord"));
446 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
449 TEST_F(SyncHttpBridgeTest, TestResponseHeader) {
450 ASSERT_TRUE(test_server_.Start());
452 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
454 GURL echo_header = test_server_.GetURL("echoall");
455 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
457 std::string test_payload = "###TEST PAYLOAD###";
458 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
459 test_payload.c_str());
461 int os_error = 0;
462 int response_code = 0;
463 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
464 EXPECT_TRUE(success);
465 EXPECT_EQ(200, response_code);
466 EXPECT_EQ(0, os_error);
468 EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html");
469 EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty());
472 TEST_F(SyncHttpBridgeTest, Abort) {
473 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
474 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
475 scoped_refptr<ShuntedHttpBridge> http_bridge(
476 new ShuntedHttpBridge(ctx_getter.get(), this, true));
477 http_bridge->SetURL("http://www.google.com", 9999);
478 http_bridge->SetPostPayload("text/plain", 2, " ");
480 int os_error = 0;
481 int response_code = 0;
483 io_thread()->task_runner()->PostTask(
484 FROM_HERE,
485 base::Bind(&SyncHttpBridgeTest::Abort, http_bridge));
486 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
487 EXPECT_FALSE(success);
488 EXPECT_EQ(net::ERR_ABORTED, os_error);
491 TEST_F(SyncHttpBridgeTest, AbortLate) {
492 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
493 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
494 scoped_refptr<ShuntedHttpBridge> http_bridge(
495 new ShuntedHttpBridge(ctx_getter.get(), this, false));
496 http_bridge->SetURL("http://www.google.com", 9999);
497 http_bridge->SetPostPayload("text/plain", 2, " ");
499 int os_error = 0;
500 int response_code = 0;
502 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
503 ASSERT_TRUE(success);
504 http_bridge->Abort();
505 // Ensures no double-free of URLFetcher, etc.
508 // Tests an interesting case where code using the HttpBridge aborts the fetch
509 // and releases ownership before a pending fetch completed callback is issued by
510 // the underlying URLFetcher (and before that URLFetcher is destroyed, which
511 // would cancel the callback).
512 TEST_F(SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) {
513 base::Thread sync_thread("SyncThread");
514 sync_thread.Start();
516 // First, block the sync thread on the post.
517 base::WaitableEvent signal_when_created(false, false);
518 base::WaitableEvent signal_when_released(false, false);
519 sync_thread.message_loop()->PostTask(FROM_HERE,
520 base::Bind(&SyncHttpBridgeTest::RunSyncThreadBridgeUseTest,
521 base::Unretained(this),
522 &signal_when_created,
523 &signal_when_released));
525 // Stop IO so we can control order of operations.
526 base::WaitableEvent io_waiter(false, false);
527 ASSERT_TRUE(io_thread()->task_runner()->PostTask(
528 FROM_HERE,
529 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter))));
531 signal_when_created.Wait(); // Wait till we have a bridge to abort.
532 ASSERT_TRUE(bridge_for_race_test());
534 // Schedule the fetch completion callback (but don't run it yet). Don't take
535 // a reference to the bridge to mimic URLFetcher's handling of the delegate.
536 net::URLFetcherDelegate* delegate =
537 static_cast<net::URLFetcherDelegate*>(bridge_for_race_test());
538 net::ResponseCookies cookies;
539 std::string response_content = "success!";
540 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL);
541 fetcher.set_response_code(200);
542 fetcher.set_cookies(cookies);
543 fetcher.SetResponseString(response_content);
544 ASSERT_TRUE(io_thread()->task_runner()->PostTask(
545 FROM_HERE,
546 base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete,
547 base::Unretained(delegate), &fetcher)));
549 // Abort the fetch. This should be smart enough to handle the case where
550 // the bridge is destroyed before the callback scheduled above completes.
551 bridge_for_race_test()->Abort();
553 // Wait until the sync thread releases its ref on the bridge.
554 signal_when_released.Wait();
555 ASSERT_FALSE(bridge_for_race_test());
557 // Unleash the hounds. The fetch completion callback should fire first, and
558 // succeed even though we Release()d the bridge above because the call to
559 // Abort should have held a reference.
560 io_waiter.Signal();
562 // Done.
563 sync_thread.Stop();
564 io_thread()->Stop();
567 void HttpBridgeRunOnSyncThread(
568 net::URLRequestContextGetter* baseline_context_getter,
569 CancelationSignal* factory_cancelation_signal,
570 syncer::HttpPostProviderFactory** bridge_factory_out,
571 syncer::HttpPostProviderInterface** bridge_out,
572 base::WaitableEvent* signal_when_created,
573 base::WaitableEvent* wait_for_shutdown) {
574 scoped_ptr<syncer::HttpBridgeFactory> bridge_factory(
575 new syncer::HttpBridgeFactory(baseline_context_getter,
576 NetworkTimeUpdateCallback(),
577 factory_cancelation_signal));
578 bridge_factory->Init("test");
579 *bridge_factory_out = bridge_factory.get();
581 HttpPostProviderInterface* bridge = bridge_factory->Create();
582 *bridge_out = bridge;
584 signal_when_created->Signal();
585 wait_for_shutdown->Wait();
587 bridge_factory->Destroy(bridge);
590 void WaitOnIOThread(base::WaitableEvent* signal_wait_start,
591 base::WaitableEvent* wait_done) {
592 signal_wait_start->Signal();
593 wait_done->Wait();
596 // Tests RequestContextGetter is properly released on IO thread even when
597 // IO thread stops before sync thread.
598 TEST_F(SyncHttpBridgeTest, RequestContextGetterReleaseOrder) {
599 base::Thread sync_thread("SyncThread");
600 sync_thread.Start();
602 syncer::HttpPostProviderFactory* factory = NULL;
603 syncer::HttpPostProviderInterface* bridge = NULL;
605 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
606 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
608 base::WaitableEvent signal_when_created(false, false);
609 base::WaitableEvent wait_for_shutdown(false, false);
611 CancelationSignal release_request_context_signal;
613 // Create bridge factory and factory on sync thread and wait for the creation
614 // to finish.
615 sync_thread.message_loop()->PostTask(FROM_HERE,
616 base::Bind(&HttpBridgeRunOnSyncThread,
617 base::Unretained(baseline_context_getter.get()),
618 &release_request_context_signal ,&factory, &bridge,
619 &signal_when_created, &wait_for_shutdown));
620 signal_when_created.Wait();
622 // Simulate sync shutdown by aborting bridge and shutting down factory on
623 // frontend.
624 bridge->Abort();
625 release_request_context_signal.Signal();
627 // Wait for sync's RequestContextGetter to be cleared on IO thread and
628 // check for reference count.
629 base::WaitableEvent signal_wait_start(false, false);
630 base::WaitableEvent wait_done(false, false);
631 io_thread()->message_loop()->PostTask(
632 FROM_HERE,
633 base::Bind(&WaitOnIOThread, &signal_wait_start, &wait_done));
634 signal_wait_start.Wait();
635 // |baseline_context_getter| should have only one reference from local
636 // variable.
637 EXPECT_TRUE(baseline_context_getter->HasOneRef());
638 baseline_context_getter = NULL;
640 // Unblock and stop IO thread before sync thread.
641 wait_done.Signal();
642 io_thread()->Stop();
644 // Unblock and stop sync thread.
645 wait_for_shutdown.Signal();
646 sync_thread.Stop();
649 // Attempt to release the URLRequestContextGetter before the HttpBridgeFactory
650 // is initialized.
651 TEST_F(SyncHttpBridgeTest, EarlyAbortFactory) {
652 // In a real scenario, the following would happen on many threads. For
653 // simplicity, this test uses only one thread.
655 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
656 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
657 CancelationSignal release_request_context_signal;
659 // UI Thread: Initialize the HttpBridgeFactory. The next step would be to
660 // post a task to SBH::Core to have it initialized.
661 scoped_ptr<syncer::HttpBridgeFactory> factory(
662 new HttpBridgeFactory(baseline_context_getter.get(),
663 NetworkTimeUpdateCallback(),
664 &release_request_context_signal));
666 // UI Thread: A very early shutdown request arrives and executes on the UI
667 // thread before the posted sync thread task is run.
668 release_request_context_signal.Signal();
670 // Sync thread: Finally run the posted task, only to find that our
671 // HttpBridgeFactory has been neutered. Should not crash.
672 factory->Init("TestUserAgent");
674 // At this point, attempting to use the factory would trigger a crash. Both
675 // this test and the real world code should make sure this never happens.
678 } // namespace syncer