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"
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
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
,
47 uLong source_length
) {
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
)
55 stream
.next_out
= dest
;
56 stream
.avail_out
= static_cast<uInt
>(*dest_length
);
57 if (static_cast<uLong
>(stream
.avail_out
) != *dest_length
)
60 stream
.zalloc
= static_cast<alloc_func
>(0);
61 stream
.zfree
= static_cast<free_func
>(0);
63 int err
= inflateInit2(&stream
, MAX_WBITS
+ kWindowBitsToGetGzipHeader
);
67 err
= inflate(&stream
, Z_FINISH
);
68 if (err
!= Z_STREAM_END
) {
70 if (err
== Z_NEED_DICT
|| (err
== Z_BUF_ERROR
&& stream
.avail_in
== 0))
74 *dest_length
= stream
.total_out
;
76 err
= inflateEnd(&stream
);
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.
84 if (compressed_data
.length() < sizeof(size
))
86 memcpy(&size
, &compressed_data
[compressed_data
.length() - 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()),
97 bit_cast
<const Bytef
*>(input
.data()),
98 static_cast<uLongf
>(input
.length())) == Z_OK
) {
99 output
->swap(uncompressed_output
);
107 const char kUserAgent
[] = "user-agent";
109 class SyncHttpBridgeTest
: public testing::Test
{
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
;
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();
142 new HttpBridge(kUserAgent
,
143 fake_default_request_context_getter_
,
144 NetworkTimeUpdateCallback());
148 static void Abort(HttpBridge
* bridge
) {
152 // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race
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_
; }
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
{
202 // If |never_finishes| is true, the simulated request never actually
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
) { }
211 void MakeAsynchronousPost() override
{
212 ASSERT_TRUE(base::MessageLoop::current() == test_
->GetIOThreadLoop());
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));
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();
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(),
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, " ");
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());
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());
333 int response_code
= 0;
334 base::FieldTrialList
field_trial_list(new base::MockEntropyProvider());
335 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression",
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
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());
367 int response_code
= 0;
368 base::FieldTrialList
field_trial_list(new base::MockEntropyProvider());
369 base::FieldTrialList::CreateFieldTrial("SyncHttpContentCompression",
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
,
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());
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
,
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());
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());
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, " ");
481 int response_code
= 0;
483 io_thread()->task_runner()->PostTask(
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, " ");
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");
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(
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(
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.
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();
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");
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
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
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(
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
637 EXPECT_TRUE(baseline_context_getter
->HasOneRef());
638 baseline_context_getter
= NULL
;
640 // Unblock and stop IO thread before sync thread.
644 // Unblock and stop sync thread.
645 wait_for_shutdown
.Signal();
649 // Attempt to release the URLRequestContextGetter before the HttpBridgeFactory
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