Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / sync / internal_api / http_bridge_unittest.cc
blob7c6fe8228eaec6df28832d8e3372397b3274827e
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 "sync/internal_api/public/http_post_provider_factory.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/zlib/zlib.h"
21 namespace syncer {
23 namespace {
25 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113.
26 const base::FilePath::CharType kDocRoot[] =
27 FILE_PATH_LITERAL("chrome/test/data");
29 // -----------------------------------------------------------------------------
30 // The rest of the code in the anon namespace is copied from
31 // components/compression/compression_utils.cc
32 // TODO(gangwu): crbug.com/515695. The following codes are copied from
33 // components/compression/compression_utils.cc, we copied them because if we
34 // reference them, we will get cycle dependency warning. Once the functions
35 // have been moved from //component to //base, we can remove the following
36 // functions.
37 //------------------------------------------------------------------------------
38 // Pass an integer greater than the following get a gzip header instead of a
39 // zlib header when calling deflateInit2() and inflateInit2().
40 const int kWindowBitsToGetGzipHeader = 16;
42 // This code is taken almost verbatim from third_party/zlib/uncompr.c. The only
43 // difference is inflateInit2() is called which sets the window bits to be > 16.
44 // That causes a gzip header to be parsed rather than a zlib header.
45 int GzipUncompressHelper(Bytef* dest,
46 uLongf* dest_length,
47 const Bytef* source,
48 uLong source_length) {
49 z_stream stream;
51 stream.next_in = bit_cast<Bytef*>(source);
52 stream.avail_in = static_cast<uInt>(source_length);
53 if (static_cast<uLong>(stream.avail_in) != source_length)
54 return Z_BUF_ERROR;
56 stream.next_out = dest;
57 stream.avail_out = static_cast<uInt>(*dest_length);
58 if (static_cast<uLong>(stream.avail_out) != *dest_length)
59 return Z_BUF_ERROR;
61 stream.zalloc = static_cast<alloc_func>(0);
62 stream.zfree = static_cast<free_func>(0);
64 int err = inflateInit2(&stream, MAX_WBITS + kWindowBitsToGetGzipHeader);
65 if (err != Z_OK)
66 return err;
68 err = inflate(&stream, Z_FINISH);
69 if (err != Z_STREAM_END) {
70 inflateEnd(&stream);
71 if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
72 return Z_DATA_ERROR;
73 return err;
75 *dest_length = stream.total_out;
77 err = inflateEnd(&stream);
78 return err;
81 // Returns the uncompressed size from GZIP-compressed |compressed_data|.
82 uint32 GetUncompressedSize(const std::string& compressed_data) {
83 // The uncompressed size is stored in the last 4 bytes of |input| in LE.
84 uint32 size;
85 if (compressed_data.length() < sizeof(size))
86 return 0;
87 memcpy(&size, &compressed_data[compressed_data.length() - sizeof(size)],
88 sizeof(size));
89 return base::ByteSwapToLE32(size);
92 bool GzipUncompress(const std::string& input, std::string* output) {
93 std::string uncompressed_output;
94 uLongf uncompressed_size = static_cast<uLongf>(GetUncompressedSize(input));
95 uncompressed_output.resize(uncompressed_size);
96 if (GzipUncompressHelper(bit_cast<Bytef*>(uncompressed_output.data()),
97 &uncompressed_size,
98 bit_cast<const Bytef*>(input.data()),
99 static_cast<uLongf>(input.length())) == Z_OK) {
100 output->swap(uncompressed_output);
101 return true;
103 return false;
106 } // namespace
108 const char kUserAgent[] = "user-agent";
110 #if defined(OS_ANDROID)
111 #define MAYBE_SyncHttpBridgeTest DISABLED_SyncHttpBridgeTest
112 #else
113 #define MAYBE_SyncHttpBridgeTest SyncHttpBridgeTest
114 #endif // defined(OS_ANDROID)
115 class MAYBE_SyncHttpBridgeTest : public testing::Test {
116 public:
117 MAYBE_SyncHttpBridgeTest()
118 : test_server_(net::SpawnedTestServer::TYPE_HTTP,
119 net::SpawnedTestServer::kLocalhost,
120 base::FilePath(kDocRoot)),
121 fake_default_request_context_getter_(NULL),
122 bridge_for_race_test_(NULL),
123 io_thread_("IO thread") {
126 void SetUp() override {
127 base::Thread::Options options;
128 options.message_loop_type = base::MessageLoop::TYPE_IO;
129 io_thread_.StartWithOptions(options);
132 void TearDown() override {
133 if (fake_default_request_context_getter_) {
134 GetIOThreadLoop()->ReleaseSoon(FROM_HERE,
135 fake_default_request_context_getter_);
136 fake_default_request_context_getter_ = NULL;
138 io_thread_.Stop();
141 HttpBridge* BuildBridge() {
142 if (!fake_default_request_context_getter_) {
143 fake_default_request_context_getter_ =
144 new net::TestURLRequestContextGetter(io_thread_.task_runner());
145 fake_default_request_context_getter_->AddRef();
147 HttpBridge* bridge =
148 new HttpBridge(kUserAgent, fake_default_request_context_getter_,
149 NetworkTimeUpdateCallback(), BindToTrackerCallback());
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,
211 bool never_finishes)
212 : HttpBridge(kUserAgent,
213 baseline_context_getter,
214 NetworkTimeUpdateCallback(),
215 BindToTrackerCallback()),
216 test_(test),
217 never_finishes_(never_finishes) {}
219 protected:
220 void MakeAsynchronousPost() override {
221 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
222 if (never_finishes_)
223 return;
225 // We don't actually want to make a request for this test, so just callback
226 // as if it completed.
227 test_->GetIOThreadLoop()->PostTask(FROM_HERE,
228 base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this));
230 private:
231 ~ShuntedHttpBridge() override {}
233 void CallOnURLFetchComplete() {
234 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
235 // We return no cookies and a dummy content response.
236 net::ResponseCookies cookies;
238 std::string response_content = "success!";
239 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL);
240 scoped_refptr<net::HttpResponseHeaders> response_headers(
241 new net::HttpResponseHeaders(""));
242 fetcher.set_response_code(200);
243 fetcher.set_cookies(cookies);
244 fetcher.SetResponseString(response_content);
245 fetcher.set_response_headers(response_headers);
246 OnURLFetchComplete(&fetcher);
248 MAYBE_SyncHttpBridgeTest* test_;
249 bool never_finishes_;
252 void MAYBE_SyncHttpBridgeTest::RunSyncThreadBridgeUseTest(
253 base::WaitableEvent* signal_when_created,
254 base::WaitableEvent* signal_when_released) {
255 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
256 new net::TestURLRequestContextGetter(io_thread_.task_runner()));
258 scoped_refptr<ShuntedHttpBridge> bridge(
259 new ShuntedHttpBridge(ctx_getter.get(), this, true));
260 bridge->SetURL("http://www.google.com", 9999);
261 bridge->SetPostPayload("text/plain", 2, " ");
262 bridge_for_race_test_ = bridge.get();
263 signal_when_created->Signal();
265 int os_error = 0;
266 int response_code = 0;
267 bridge->MakeSynchronousPost(&os_error, &response_code);
268 bridge_for_race_test_ = NULL;
270 signal_when_released->Signal();
273 TEST_F(MAYBE_SyncHttpBridgeTest, TestUsesSameHttpNetworkSession) {
274 // Run this test on the IO thread because we can only call
275 // URLRequestContextGetter::GetURLRequestContext on the IO thread.
276 io_thread()->message_loop()->PostTask(
277 FROM_HERE,
278 base::Bind(&MAYBE_SyncHttpBridgeTest::TestSameHttpNetworkSession,
279 base::MessageLoop::current(), this));
280 base::MessageLoop::current()->Run();
283 // Test the HttpBridge without actually making any network requests.
284 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostShunted) {
285 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
286 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
287 scoped_refptr<HttpBridge> http_bridge(
288 new ShuntedHttpBridge(ctx_getter.get(), this, false));
289 http_bridge->SetURL("http://www.google.com", 9999);
290 http_bridge->SetPostPayload("text/plain", 2, " ");
292 int os_error = 0;
293 int response_code = 0;
294 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
295 EXPECT_TRUE(success);
296 EXPECT_EQ(200, response_code);
297 EXPECT_EQ(0, os_error);
299 EXPECT_EQ(8, http_bridge->GetResponseContentLength());
300 EXPECT_EQ(std::string("success!"),
301 std::string(http_bridge->GetResponseContent()));
304 // Full round-trip test of the HttpBridge, using default UA string and
305 // no request cookies.
306 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
307 ASSERT_TRUE(test_server_.Start());
309 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
311 std::string payload = "this should be echoed back";
312 GURL echo = test_server_.GetURL("echo");
313 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
314 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
315 payload.length() + 1, payload.c_str());
316 int os_error = 0;
317 int response_code = 0;
318 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
319 EXPECT_TRUE(success);
320 EXPECT_EQ(200, response_code);
321 EXPECT_EQ(0, os_error);
323 EXPECT_EQ(payload.length() + 1,
324 static_cast<size_t>(http_bridge->GetResponseContentLength()));
325 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent()));
328 // Full round-trip test of the HttpBridge with compressed data, check if the
329 // data is correctly compressed.
330 TEST_F(MAYBE_SyncHttpBridgeTest, CompressedRequestPayloadCheck) {
331 ASSERT_TRUE(test_server_.Start());
333 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
335 std::string payload = "this should be echoed back";
336 GURL echo = test_server_.GetURL("echo");
337 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
338 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
339 payload.length(), payload.c_str());
340 int os_error = 0;
341 int response_code = 0;
342 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
343 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression",
344 "Enabled");
345 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
346 EXPECT_TRUE(success);
347 EXPECT_EQ(200, response_code);
348 EXPECT_EQ(0, os_error);
350 EXPECT_NE(payload.length() + 1,
351 static_cast<size_t>(http_bridge->GetResponseContentLength()));
352 std::string compressed_payload(http_bridge->GetResponseContent(),
353 http_bridge->GetResponseContentLength());
354 std::string uncompressed_payload;
355 GzipUncompress(compressed_payload, &uncompressed_payload);
356 EXPECT_EQ(payload, uncompressed_payload);
359 // Full round-trip test of the HttpBridge with compression, check if header
360 // fields("Content-Encoding" ,"Accept-Encoding" and user agent) are set
361 // correctly.
362 TEST_F(MAYBE_SyncHttpBridgeTest, CompressedRequestHeaderCheck) {
363 ASSERT_TRUE(test_server_.Start());
365 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
367 GURL echo_header = test_server_.GetURL("echoall");
368 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
370 std::string test_payload = "###TEST PAYLOAD###";
371 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
372 test_payload.c_str());
374 int os_error = 0;
375 int response_code = 0;
376 base::FieldTrialList field_trial_list(new base::MockEntropyProvider());
377 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression",
378 "Enabled");
379 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
380 EXPECT_TRUE(success);
381 EXPECT_EQ(200, response_code);
382 EXPECT_EQ(0, os_error);
384 std::string response(http_bridge->GetResponseContent(),
385 http_bridge->GetResponseContentLength());
386 EXPECT_NE(std::string::npos, response.find("Content-Encoding: gzip"));
387 EXPECT_NE(std::string::npos,
388 response.find(base::StringPrintf(
389 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding,
390 "gzip, deflate")));
391 EXPECT_NE(std::string::npos,
392 response.find(base::StringPrintf(
393 "%s: %s", net::HttpRequestHeaders::kUserAgent, kUserAgent)));
396 // Full round-trip test of the HttpBridge.
397 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
398 ASSERT_TRUE(test_server_.Start());
400 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
402 GURL echo_header = test_server_.GetURL("echoall");
403 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
405 std::string test_payload = "###TEST PAYLOAD###";
406 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
407 test_payload.c_str());
409 int os_error = 0;
410 int response_code = 0;
411 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
412 EXPECT_TRUE(success);
413 EXPECT_EQ(200, response_code);
414 EXPECT_EQ(0, os_error);
416 std::string response(http_bridge->GetResponseContent(),
417 http_bridge->GetResponseContentLength());
418 EXPECT_EQ(std::string::npos, response.find("Cookie:"));
419 EXPECT_NE(std::string::npos,
420 response.find(base::StringPrintf(
421 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding,
422 "deflate")));
423 EXPECT_NE(std::string::npos,
424 response.find(base::StringPrintf("%s: %s",
425 net::HttpRequestHeaders::kUserAgent, kUserAgent)));
426 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
429 TEST_F(MAYBE_SyncHttpBridgeTest, TestExtraRequestHeaders) {
430 ASSERT_TRUE(test_server_.Start());
432 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
434 GURL echo_header = test_server_.GetURL("echoall");
436 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
437 http_bridge->SetExtraRequestHeaders("test:fnord");
439 std::string test_payload = "###TEST PAYLOAD###";
440 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
441 test_payload.c_str());
443 int os_error = 0;
444 int response_code = 0;
445 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
446 EXPECT_TRUE(success);
447 EXPECT_EQ(200, response_code);
448 EXPECT_EQ(0, os_error);
450 std::string response(http_bridge->GetResponseContent(),
451 http_bridge->GetResponseContentLength());
453 EXPECT_NE(std::string::npos, response.find("fnord"));
454 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
457 TEST_F(MAYBE_SyncHttpBridgeTest, TestResponseHeader) {
458 ASSERT_TRUE(test_server_.Start());
460 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
462 GURL echo_header = test_server_.GetURL("echoall");
463 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
465 std::string test_payload = "###TEST PAYLOAD###";
466 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
467 test_payload.c_str());
469 int os_error = 0;
470 int response_code = 0;
471 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
472 EXPECT_TRUE(success);
473 EXPECT_EQ(200, response_code);
474 EXPECT_EQ(0, os_error);
476 EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html");
477 EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty());
480 TEST_F(MAYBE_SyncHttpBridgeTest, Abort) {
481 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
482 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
483 scoped_refptr<ShuntedHttpBridge> http_bridge(
484 new ShuntedHttpBridge(ctx_getter.get(), this, true));
485 http_bridge->SetURL("http://www.google.com", 9999);
486 http_bridge->SetPostPayload("text/plain", 2, " ");
488 int os_error = 0;
489 int response_code = 0;
491 io_thread()->task_runner()->PostTask(
492 FROM_HERE,
493 base::Bind(&MAYBE_SyncHttpBridgeTest::Abort, http_bridge));
494 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
495 EXPECT_FALSE(success);
496 EXPECT_EQ(net::ERR_ABORTED, os_error);
499 TEST_F(MAYBE_SyncHttpBridgeTest, AbortLate) {
500 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
501 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
502 scoped_refptr<ShuntedHttpBridge> http_bridge(
503 new ShuntedHttpBridge(ctx_getter.get(), this, false));
504 http_bridge->SetURL("http://www.google.com", 9999);
505 http_bridge->SetPostPayload("text/plain", 2, " ");
507 int os_error = 0;
508 int response_code = 0;
510 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
511 ASSERT_TRUE(success);
512 http_bridge->Abort();
513 // Ensures no double-free of URLFetcher, etc.
516 // Tests an interesting case where code using the HttpBridge aborts the fetch
517 // and releases ownership before a pending fetch completed callback is issued by
518 // the underlying URLFetcher (and before that URLFetcher is destroyed, which
519 // would cancel the callback).
520 TEST_F(MAYBE_SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) {
521 base::Thread sync_thread("SyncThread");
522 sync_thread.Start();
524 // First, block the sync thread on the post.
525 base::WaitableEvent signal_when_created(false, false);
526 base::WaitableEvent signal_when_released(false, false);
527 sync_thread.message_loop()->PostTask(FROM_HERE,
528 base::Bind(&MAYBE_SyncHttpBridgeTest::RunSyncThreadBridgeUseTest,
529 base::Unretained(this),
530 &signal_when_created,
531 &signal_when_released));
533 // Stop IO so we can control order of operations.
534 base::WaitableEvent io_waiter(false, false);
535 ASSERT_TRUE(io_thread()->task_runner()->PostTask(
536 FROM_HERE,
537 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter))));
539 signal_when_created.Wait(); // Wait till we have a bridge to abort.
540 ASSERT_TRUE(bridge_for_race_test());
542 // Schedule the fetch completion callback (but don't run it yet). Don't take
543 // a reference to the bridge to mimic URLFetcher's handling of the delegate.
544 net::URLFetcherDelegate* delegate =
545 static_cast<net::URLFetcherDelegate*>(bridge_for_race_test());
546 net::ResponseCookies cookies;
547 std::string response_content = "success!";
548 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL);
549 fetcher.set_response_code(200);
550 fetcher.set_cookies(cookies);
551 fetcher.SetResponseString(response_content);
552 ASSERT_TRUE(io_thread()->task_runner()->PostTask(
553 FROM_HERE,
554 base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete,
555 base::Unretained(delegate), &fetcher)));
557 // Abort the fetch. This should be smart enough to handle the case where
558 // the bridge is destroyed before the callback scheduled above completes.
559 bridge_for_race_test()->Abort();
561 // Wait until the sync thread releases its ref on the bridge.
562 signal_when_released.Wait();
563 ASSERT_FALSE(bridge_for_race_test());
565 // Unleash the hounds. The fetch completion callback should fire first, and
566 // succeed even though we Release()d the bridge above because the call to
567 // Abort should have held a reference.
568 io_waiter.Signal();
570 // Done.
571 sync_thread.Stop();
572 io_thread()->Stop();
575 void HttpBridgeRunOnSyncThread(
576 net::URLRequestContextGetter* baseline_context_getter,
577 CancelationSignal* factory_cancelation_signal,
578 syncer::HttpPostProviderFactory** bridge_factory_out,
579 syncer::HttpPostProviderInterface** bridge_out,
580 base::WaitableEvent* signal_when_created,
581 base::WaitableEvent* wait_for_shutdown) {
582 scoped_ptr<syncer::HttpBridgeFactory> bridge_factory(
583 new syncer::HttpBridgeFactory(baseline_context_getter,
584 NetworkTimeUpdateCallback(),
585 factory_cancelation_signal));
586 bridge_factory->Init("test", BindToTrackerCallback());
587 *bridge_factory_out = bridge_factory.get();
589 HttpPostProviderInterface* bridge = bridge_factory->Create();
590 *bridge_out = bridge;
592 signal_when_created->Signal();
593 wait_for_shutdown->Wait();
595 bridge_factory->Destroy(bridge);
598 void WaitOnIOThread(base::WaitableEvent* signal_wait_start,
599 base::WaitableEvent* wait_done) {
600 signal_wait_start->Signal();
601 wait_done->Wait();
604 // Tests RequestContextGetter is properly released on IO thread even when
605 // IO thread stops before sync thread.
606 TEST_F(MAYBE_SyncHttpBridgeTest, RequestContextGetterReleaseOrder) {
607 base::Thread sync_thread("SyncThread");
608 sync_thread.Start();
610 syncer::HttpPostProviderFactory* factory = NULL;
611 syncer::HttpPostProviderInterface* bridge = NULL;
613 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
614 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
616 base::WaitableEvent signal_when_created(false, false);
617 base::WaitableEvent wait_for_shutdown(false, false);
619 CancelationSignal release_request_context_signal;
621 // Create bridge factory and factory on sync thread and wait for the creation
622 // to finish.
623 sync_thread.message_loop()->PostTask(FROM_HERE,
624 base::Bind(&HttpBridgeRunOnSyncThread,
625 base::Unretained(baseline_context_getter.get()),
626 &release_request_context_signal ,&factory, &bridge,
627 &signal_when_created, &wait_for_shutdown));
628 signal_when_created.Wait();
630 // Simulate sync shutdown by aborting bridge and shutting down factory on
631 // frontend.
632 bridge->Abort();
633 release_request_context_signal.Signal();
635 // Wait for sync's RequestContextGetter to be cleared on IO thread and
636 // check for reference count.
637 base::WaitableEvent signal_wait_start(false, false);
638 base::WaitableEvent wait_done(false, false);
639 io_thread()->message_loop()->PostTask(
640 FROM_HERE,
641 base::Bind(&WaitOnIOThread, &signal_wait_start, &wait_done));
642 signal_wait_start.Wait();
643 // |baseline_context_getter| should have only one reference from local
644 // variable.
645 EXPECT_TRUE(baseline_context_getter->HasOneRef());
646 baseline_context_getter = NULL;
648 // Unblock and stop IO thread before sync thread.
649 wait_done.Signal();
650 io_thread()->Stop();
652 // Unblock and stop sync thread.
653 wait_for_shutdown.Signal();
654 sync_thread.Stop();
657 // Attempt to release the URLRequestContextGetter before the HttpBridgeFactory
658 // is initialized.
659 TEST_F(MAYBE_SyncHttpBridgeTest, EarlyAbortFactory) {
660 // In a real scenario, the following would happen on many threads. For
661 // simplicity, this test uses only one thread.
663 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
664 new net::TestURLRequestContextGetter(io_thread()->task_runner()));
665 CancelationSignal release_request_context_signal;
667 // UI Thread: Initialize the HttpBridgeFactory. The next step would be to
668 // post a task to SBH::Core to have it initialized.
669 scoped_ptr<syncer::HttpBridgeFactory> factory(
670 new HttpBridgeFactory(baseline_context_getter.get(),
671 NetworkTimeUpdateCallback(),
672 &release_request_context_signal));
674 // UI Thread: A very early shutdown request arrives and executes on the UI
675 // thread before the posted sync thread task is run.
676 release_request_context_signal.Signal();
678 // Sync thread: Finally run the posted task, only to find that our
679 // HttpBridgeFactory has been neutered. Should not crash.
680 factory->Init("TestUserAgent", BindToTrackerCallback());
682 // At this point, attempting to use the factory would trigger a crash. Both
683 // this test and the real world code should make sure this never happens.
686 } // namespace syncer