OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <stddef.h> | |
6 #include <stdint.h> | |
7 | |
8 #include "base/bit_cast.h" | |
9 #include "base/run_loop.h" | |
10 #include "base/single_thread_task_runner.h" | |
11 #include "base/strings/stringprintf.h" | |
12 #include "base/synchronization/waitable_event.h" | |
13 #include "base/threading/thread.h" | |
14 #include "build/build_config.h" | |
15 #include "net/http/http_response_headers.h" | |
16 #include "net/test/embedded_test_server/embedded_test_server.h" | |
17 #include "net/url_request/test_url_fetcher_factory.h" | |
18 #include "net/url_request/url_fetcher_delegate.h" | |
19 #include "net/url_request/url_request_test_util.h" | |
20 #include "sync/internal_api/public/base/cancelation_signal.h" | |
21 #include "sync/internal_api/public/http_bridge.h" | |
22 #include "sync/internal_api/public/http_post_provider_factory.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 namespace syncer { | |
26 | |
27 namespace { | |
28 | |
29 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113. | |
30 const base::FilePath::CharType kDocRoot[] = | |
31 FILE_PATH_LITERAL("chrome/test/data"); | |
32 | |
33 } // namespace | |
34 | |
35 const char kUserAgent[] = "user-agent"; | |
36 | |
37 #if defined(OS_ANDROID) | |
38 #define MAYBE_SyncHttpBridgeTest DISABLED_SyncHttpBridgeTest | |
39 #else | |
40 #define MAYBE_SyncHttpBridgeTest SyncHttpBridgeTest | |
41 #endif // defined(OS_ANDROID) | |
42 class MAYBE_SyncHttpBridgeTest : public testing::Test { | |
43 public: | |
44 MAYBE_SyncHttpBridgeTest() | |
45 : fake_default_request_context_getter_(NULL), | |
46 bridge_for_race_test_(NULL), | |
47 io_thread_("IO thread") { | |
48 test_server_.AddDefaultHandlers(base::FilePath(kDocRoot)); | |
49 } | |
50 | |
51 void SetUp() override { | |
52 base::Thread::Options options; | |
53 options.message_loop_type = base::MessageLoop::TYPE_IO; | |
54 io_thread_.StartWithOptions(options); | |
55 } | |
56 | |
57 void TearDown() override { | |
58 if (fake_default_request_context_getter_) { | |
59 GetIOThreadLoop()->task_runner()->ReleaseSoon( | |
60 FROM_HERE, fake_default_request_context_getter_); | |
61 fake_default_request_context_getter_ = NULL; | |
62 } | |
63 io_thread_.Stop(); | |
64 } | |
65 | |
66 HttpBridge* BuildBridge() { | |
67 if (!fake_default_request_context_getter_) { | |
68 fake_default_request_context_getter_ = | |
69 new net::TestURLRequestContextGetter(io_thread_.task_runner()); | |
70 fake_default_request_context_getter_->AddRef(); | |
71 } | |
72 HttpBridge* bridge = | |
73 new HttpBridge(kUserAgent, fake_default_request_context_getter_, | |
74 NetworkTimeUpdateCallback(), BindToTrackerCallback()); | |
75 return bridge; | |
76 } | |
77 | |
78 static void Abort(HttpBridge* bridge) { | |
79 bridge->Abort(); | |
80 } | |
81 | |
82 // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race | |
83 // condition. | |
84 void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created, | |
85 base::WaitableEvent* signal_when_released); | |
86 | |
87 static void TestSameHttpNetworkSession(base::MessageLoop* main_message_loop, | |
88 MAYBE_SyncHttpBridgeTest* test) { | |
89 scoped_refptr<HttpBridge> http_bridge(test->BuildBridge()); | |
90 EXPECT_TRUE(test->GetTestRequestContextGetter()); | |
91 net::HttpNetworkSession* test_session = | |
92 test->GetTestRequestContextGetter()->GetURLRequestContext()-> | |
93 http_transaction_factory()->GetSession(); | |
94 EXPECT_EQ(test_session, | |
95 http_bridge->GetRequestContextGetterForTest()-> | |
96 GetURLRequestContext()-> | |
97 http_transaction_factory()->GetSession()); | |
98 main_message_loop->task_runner()->PostTask( | |
99 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
100 } | |
101 | |
102 base::MessageLoop* GetIOThreadLoop() { return io_thread_.message_loop(); } | |
103 | |
104 // Note this is lazy created, so don't call this before your bridge. | |
105 net::TestURLRequestContextGetter* GetTestRequestContextGetter() { | |
106 return fake_default_request_context_getter_; | |
107 } | |
108 | |
109 net::EmbeddedTestServer test_server_; | |
110 | |
111 base::Thread* io_thread() { return &io_thread_; } | |
112 | |
113 HttpBridge* bridge_for_race_test() { return bridge_for_race_test_; } | |
114 | |
115 private: | |
116 // A make-believe "default" request context, as would be returned by | |
117 // Profile::GetDefaultRequestContext(). Created lazily by BuildBridge. | |
118 net::TestURLRequestContextGetter* fake_default_request_context_getter_; | |
119 | |
120 HttpBridge* bridge_for_race_test_; | |
121 | |
122 // Separate thread for IO used by the HttpBridge. | |
123 base::Thread io_thread_; | |
124 base::MessageLoop loop_; | |
125 }; | |
126 | |
127 // An HttpBridge that doesn't actually make network requests and just calls | |
128 // back with dummy response info. | |
129 // TODO(tim): Instead of inheriting here we should inject a component | |
130 // responsible for the MakeAsynchronousPost bit. | |
131 class ShuntedHttpBridge : public HttpBridge { | |
132 public: | |
133 // If |never_finishes| is true, the simulated request never actually | |
134 // returns. | |
135 ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter, | |
136 MAYBE_SyncHttpBridgeTest* test, | |
137 bool never_finishes) | |
138 : HttpBridge(kUserAgent, | |
139 baseline_context_getter, | |
140 NetworkTimeUpdateCallback(), | |
141 BindToTrackerCallback()), | |
142 test_(test), | |
143 never_finishes_(never_finishes) {} | |
144 | |
145 protected: | |
146 void MakeAsynchronousPost() override { | |
147 ASSERT_TRUE( | |
148 test_->GetIOThreadLoop()->task_runner()->BelongsToCurrentThread()); | |
149 if (never_finishes_) | |
150 return; | |
151 | |
152 // We don't actually want to make a request for this test, so just callback | |
153 // as if it completed. | |
154 test_->GetIOThreadLoop()->task_runner()->PostTask( | |
155 FROM_HERE, | |
156 base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this)); | |
157 } | |
158 | |
159 private: | |
160 ~ShuntedHttpBridge() override {} | |
161 | |
162 void CallOnURLFetchComplete() { | |
163 ASSERT_TRUE( | |
164 test_->GetIOThreadLoop()->task_runner()->BelongsToCurrentThread()); | |
165 // We return a dummy content response. | |
166 std::string response_content = "success!"; | |
167 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL); | |
168 scoped_refptr<net::HttpResponseHeaders> response_headers( | |
169 new net::HttpResponseHeaders("")); | |
170 fetcher.set_response_code(200); | |
171 fetcher.SetResponseString(response_content); | |
172 fetcher.set_response_headers(response_headers); | |
173 OnURLFetchComplete(&fetcher); | |
174 } | |
175 MAYBE_SyncHttpBridgeTest* test_; | |
176 bool never_finishes_; | |
177 }; | |
178 | |
179 void MAYBE_SyncHttpBridgeTest::RunSyncThreadBridgeUseTest( | |
180 base::WaitableEvent* signal_when_created, | |
181 base::WaitableEvent* signal_when_released) { | |
182 scoped_refptr<net::URLRequestContextGetter> ctx_getter( | |
183 new net::TestURLRequestContextGetter(io_thread_.task_runner())); | |
184 { | |
185 scoped_refptr<ShuntedHttpBridge> bridge( | |
186 new ShuntedHttpBridge(ctx_getter.get(), this, true)); | |
187 bridge->SetURL("http://www.google.com", 9999); | |
188 bridge->SetPostPayload("text/plain", 2, " "); | |
189 bridge_for_race_test_ = bridge.get(); | |
190 signal_when_created->Signal(); | |
191 | |
192 int os_error = 0; | |
193 int response_code = 0; | |
194 bridge->MakeSynchronousPost(&os_error, &response_code); | |
195 bridge_for_race_test_ = NULL; | |
196 } | |
197 signal_when_released->Signal(); | |
198 } | |
199 | |
200 TEST_F(MAYBE_SyncHttpBridgeTest, TestUsesSameHttpNetworkSession) { | |
201 // Run this test on the IO thread because we can only call | |
202 // URLRequestContextGetter::GetURLRequestContext on the IO thread. | |
203 io_thread()->task_runner()->PostTask( | |
204 FROM_HERE, | |
205 base::Bind(&MAYBE_SyncHttpBridgeTest::TestSameHttpNetworkSession, | |
206 base::MessageLoop::current(), this)); | |
207 base::RunLoop().Run(); | |
208 } | |
209 | |
210 // Test the HttpBridge without actually making any network requests. | |
211 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostShunted) { | |
212 scoped_refptr<net::URLRequestContextGetter> ctx_getter( | |
213 new net::TestURLRequestContextGetter(io_thread()->task_runner())); | |
214 scoped_refptr<HttpBridge> http_bridge( | |
215 new ShuntedHttpBridge(ctx_getter.get(), this, false)); | |
216 http_bridge->SetURL("http://www.google.com", 9999); | |
217 http_bridge->SetPostPayload("text/plain", 2, " "); | |
218 | |
219 int os_error = 0; | |
220 int response_code = 0; | |
221 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | |
222 EXPECT_TRUE(success); | |
223 EXPECT_EQ(200, response_code); | |
224 EXPECT_EQ(0, os_error); | |
225 | |
226 EXPECT_EQ(8, http_bridge->GetResponseContentLength()); | |
227 EXPECT_EQ(std::string("success!"), | |
228 std::string(http_bridge->GetResponseContent())); | |
229 } | |
230 | |
231 // Full round-trip test of the HttpBridge, using default UA string and | |
232 // no request cookies. | |
233 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) { | |
234 ASSERT_TRUE(test_server_.Start()); | |
235 | |
236 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); | |
237 | |
238 std::string payload = "this should be echoed back"; | |
239 GURL echo = test_server_.GetURL("/echo"); | |
240 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort()); | |
241 http_bridge->SetPostPayload("application/x-www-form-urlencoded", | |
242 payload.length() + 1, payload.c_str()); | |
243 int os_error = 0; | |
244 int response_code = 0; | |
245 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | |
246 EXPECT_TRUE(success); | |
247 EXPECT_EQ(200, response_code); | |
248 EXPECT_EQ(0, os_error); | |
249 | |
250 EXPECT_EQ(payload.length() + 1, | |
251 static_cast<size_t>(http_bridge->GetResponseContentLength())); | |
252 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent())); | |
253 } | |
254 | |
255 // Full round-trip test of the HttpBridge with compression, check if header | |
256 // fields("Content-Encoding" ,"Accept-Encoding" and user agent) are set | |
257 // correctly. | |
258 TEST_F(MAYBE_SyncHttpBridgeTest, CompressedRequestHeaderCheck) { | |
259 ASSERT_TRUE(test_server_.Start()); | |
260 | |
261 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); | |
262 | |
263 GURL echo_header = test_server_.GetURL("/echoall"); | |
264 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); | |
265 | |
266 std::string test_payload = "###TEST PAYLOAD###"; | |
267 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, | |
268 test_payload.c_str()); | |
269 | |
270 int os_error = 0; | |
271 int response_code = 0; | |
272 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | |
273 EXPECT_TRUE(success); | |
274 EXPECT_EQ(200, response_code); | |
275 EXPECT_EQ(0, os_error); | |
276 | |
277 std::string response(http_bridge->GetResponseContent(), | |
278 http_bridge->GetResponseContentLength()); | |
279 EXPECT_NE(std::string::npos, | |
280 response.find(base::StringPrintf( | |
281 "%s: %s", net::HttpRequestHeaders::kAcceptEncoding, | |
282 "gzip, deflate"))); | |
283 EXPECT_NE(std::string::npos, | |
284 response.find(base::StringPrintf( | |
285 "%s: %s", net::HttpRequestHeaders::kUserAgent, kUserAgent))); | |
286 } | |
287 | |
288 // Full round-trip test of the HttpBridge. | |
289 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) { | |
290 ASSERT_TRUE(test_server_.Start()); | |
291 | |
292 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); | |
293 | |
294 GURL echo_header = test_server_.GetURL("/echoall"); | |
295 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); | |
296 | |
297 std::string test_payload = "###TEST PAYLOAD###"; | |
298 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, | |
299 test_payload.c_str()); | |
300 | |
301 int os_error = 0; | |
302 int response_code = 0; | |
303 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | |
304 EXPECT_TRUE(success); | |
305 EXPECT_EQ(200, response_code); | |
306 EXPECT_EQ(0, os_error); | |
307 | |
308 std::string response(http_bridge->GetResponseContent(), | |
309 http_bridge->GetResponseContentLength()); | |
310 EXPECT_EQ(std::string::npos, response.find("Cookie:")); | |
311 EXPECT_NE(std::string::npos, | |
312 response.find(base::StringPrintf("%s: %s", | |
313 net::HttpRequestHeaders::kUserAgent, kUserAgent))); | |
314 EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); | |
315 } | |
316 | |
317 TEST_F(MAYBE_SyncHttpBridgeTest, TestExtraRequestHeaders) { | |
318 ASSERT_TRUE(test_server_.Start()); | |
319 | |
320 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); | |
321 | |
322 GURL echo_header = test_server_.GetURL("/echoall"); | |
323 | |
324 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); | |
325 http_bridge->SetExtraRequestHeaders("test:fnord"); | |
326 | |
327 std::string test_payload = "###TEST PAYLOAD###"; | |
328 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, | |
329 test_payload.c_str()); | |
330 | |
331 int os_error = 0; | |
332 int response_code = 0; | |
333 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | |
334 EXPECT_TRUE(success); | |
335 EXPECT_EQ(200, response_code); | |
336 EXPECT_EQ(0, os_error); | |
337 | |
338 std::string response(http_bridge->GetResponseContent(), | |
339 http_bridge->GetResponseContentLength()); | |
340 | |
341 EXPECT_NE(std::string::npos, response.find("fnord")); | |
342 EXPECT_NE(std::string::npos, response.find(test_payload.c_str())); | |
343 } | |
344 | |
345 TEST_F(MAYBE_SyncHttpBridgeTest, TestResponseHeader) { | |
346 ASSERT_TRUE(test_server_.Start()); | |
347 | |
348 scoped_refptr<HttpBridge> http_bridge(BuildBridge()); | |
349 | |
350 GURL echo_header = test_server_.GetURL("/echoall"); | |
351 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort()); | |
352 | |
353 std::string test_payload = "###TEST PAYLOAD###"; | |
354 http_bridge->SetPostPayload("text/html", test_payload.length() + 1, | |
355 test_payload.c_str()); | |
356 | |
357 int os_error = 0; | |
358 int response_code = 0; | |
359 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | |
360 EXPECT_TRUE(success); | |
361 EXPECT_EQ(200, response_code); | |
362 EXPECT_EQ(0, os_error); | |
363 | |
364 EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html"); | |
365 EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty()); | |
366 } | |
367 | |
368 TEST_F(MAYBE_SyncHttpBridgeTest, Abort) { | |
369 scoped_refptr<net::URLRequestContextGetter> ctx_getter( | |
370 new net::TestURLRequestContextGetter(io_thread()->task_runner())); | |
371 scoped_refptr<ShuntedHttpBridge> http_bridge( | |
372 new ShuntedHttpBridge(ctx_getter.get(), this, true)); | |
373 http_bridge->SetURL("http://www.google.com", 9999); | |
374 http_bridge->SetPostPayload("text/plain", 2, " "); | |
375 | |
376 int os_error = 0; | |
377 int response_code = 0; | |
378 | |
379 io_thread()->task_runner()->PostTask( | |
380 FROM_HERE, base::Bind(&MAYBE_SyncHttpBridgeTest::Abort, | |
381 base::RetainedRef(http_bridge))); | |
382 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | |
383 EXPECT_FALSE(success); | |
384 EXPECT_EQ(net::ERR_ABORTED, os_error); | |
385 } | |
386 | |
387 TEST_F(MAYBE_SyncHttpBridgeTest, AbortLate) { | |
388 scoped_refptr<net::URLRequestContextGetter> ctx_getter( | |
389 new net::TestURLRequestContextGetter(io_thread()->task_runner())); | |
390 scoped_refptr<ShuntedHttpBridge> http_bridge( | |
391 new ShuntedHttpBridge(ctx_getter.get(), this, false)); | |
392 http_bridge->SetURL("http://www.google.com", 9999); | |
393 http_bridge->SetPostPayload("text/plain", 2, " "); | |
394 | |
395 int os_error = 0; | |
396 int response_code = 0; | |
397 | |
398 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code); | |
399 ASSERT_TRUE(success); | |
400 http_bridge->Abort(); | |
401 // Ensures no double-free of URLFetcher, etc. | |
402 } | |
403 | |
404 // Tests an interesting case where code using the HttpBridge aborts the fetch | |
405 // and releases ownership before a pending fetch completed callback is issued by | |
406 // the underlying URLFetcher (and before that URLFetcher is destroyed, which | |
407 // would cancel the callback). | |
408 TEST_F(MAYBE_SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) { | |
409 base::Thread sync_thread("SyncThread"); | |
410 sync_thread.Start(); | |
411 | |
412 // First, block the sync thread on the post. | |
413 base::WaitableEvent signal_when_created( | |
414 base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
415 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
416 base::WaitableEvent signal_when_released( | |
417 base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
418 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
419 sync_thread.task_runner()->PostTask( | |
420 FROM_HERE, | |
421 base::Bind(&MAYBE_SyncHttpBridgeTest::RunSyncThreadBridgeUseTest, | |
422 base::Unretained(this), &signal_when_created, | |
423 &signal_when_released)); | |
424 | |
425 // Stop IO so we can control order of operations. | |
426 base::WaitableEvent io_waiter( | |
427 base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
428 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
429 ASSERT_TRUE(io_thread()->task_runner()->PostTask( | |
430 FROM_HERE, | |
431 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter)))); | |
432 | |
433 signal_when_created.Wait(); // Wait till we have a bridge to abort. | |
434 ASSERT_TRUE(bridge_for_race_test()); | |
435 | |
436 // Schedule the fetch completion callback (but don't run it yet). Don't take | |
437 // a reference to the bridge to mimic URLFetcher's handling of the delegate. | |
438 net::URLFetcherDelegate* delegate = | |
439 static_cast<net::URLFetcherDelegate*>(bridge_for_race_test()); | |
440 std::string response_content = "success!"; | |
441 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL); | |
442 fetcher.set_response_code(200); | |
443 fetcher.SetResponseString(response_content); | |
444 ASSERT_TRUE(io_thread()->task_runner()->PostTask( | |
445 FROM_HERE, | |
446 base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete, | |
447 base::Unretained(delegate), &fetcher))); | |
448 | |
449 // Abort the fetch. This should be smart enough to handle the case where | |
450 // the bridge is destroyed before the callback scheduled above completes. | |
451 bridge_for_race_test()->Abort(); | |
452 | |
453 // Wait until the sync thread releases its ref on the bridge. | |
454 signal_when_released.Wait(); | |
455 ASSERT_FALSE(bridge_for_race_test()); | |
456 | |
457 // Unleash the hounds. The fetch completion callback should fire first, and | |
458 // succeed even though we Release()d the bridge above because the call to | |
459 // Abort should have held a reference. | |
460 io_waiter.Signal(); | |
461 | |
462 // Done. | |
463 sync_thread.Stop(); | |
464 io_thread()->Stop(); | |
465 } | |
466 | |
467 void HttpBridgeRunOnSyncThread( | |
468 net::URLRequestContextGetter* baseline_context_getter, | |
469 CancelationSignal* factory_cancelation_signal, | |
470 syncer::HttpPostProviderFactory** bridge_factory_out, | |
471 syncer::HttpPostProviderInterface** bridge_out, | |
472 base::WaitableEvent* signal_when_created, | |
473 base::WaitableEvent* wait_for_shutdown) { | |
474 std::unique_ptr<syncer::HttpBridgeFactory> bridge_factory( | |
475 new syncer::HttpBridgeFactory(baseline_context_getter, | |
476 NetworkTimeUpdateCallback(), | |
477 factory_cancelation_signal)); | |
478 bridge_factory->Init("test", BindToTrackerCallback()); | |
479 *bridge_factory_out = bridge_factory.get(); | |
480 | |
481 HttpPostProviderInterface* bridge = bridge_factory->Create(); | |
482 *bridge_out = bridge; | |
483 | |
484 signal_when_created->Signal(); | |
485 wait_for_shutdown->Wait(); | |
486 | |
487 bridge_factory->Destroy(bridge); | |
488 } | |
489 | |
490 void WaitOnIOThread(base::WaitableEvent* signal_wait_start, | |
491 base::WaitableEvent* wait_done) { | |
492 signal_wait_start->Signal(); | |
493 wait_done->Wait(); | |
494 } | |
495 | |
496 // Tests RequestContextGetter is properly released on IO thread even when | |
497 // IO thread stops before sync thread. | |
498 TEST_F(MAYBE_SyncHttpBridgeTest, RequestContextGetterReleaseOrder) { | |
499 base::Thread sync_thread("SyncThread"); | |
500 sync_thread.Start(); | |
501 | |
502 syncer::HttpPostProviderFactory* factory = NULL; | |
503 syncer::HttpPostProviderInterface* bridge = NULL; | |
504 | |
505 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter( | |
506 new net::TestURLRequestContextGetter(io_thread()->task_runner())); | |
507 | |
508 base::WaitableEvent signal_when_created( | |
509 base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
510 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
511 base::WaitableEvent wait_for_shutdown( | |
512 base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
513 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
514 | |
515 CancelationSignal release_request_context_signal; | |
516 | |
517 // Create bridge factory and factory on sync thread and wait for the creation | |
518 // to finish. | |
519 sync_thread.task_runner()->PostTask( | |
520 FROM_HERE, base::Bind(&HttpBridgeRunOnSyncThread, | |
521 base::Unretained(baseline_context_getter.get()), | |
522 &release_request_context_signal, &factory, &bridge, | |
523 &signal_when_created, &wait_for_shutdown)); | |
524 signal_when_created.Wait(); | |
525 | |
526 // Simulate sync shutdown by aborting bridge and shutting down factory on | |
527 // frontend. | |
528 bridge->Abort(); | |
529 release_request_context_signal.Signal(); | |
530 | |
531 // Wait for sync's RequestContextGetter to be cleared on IO thread and | |
532 // check for reference count. | |
533 base::WaitableEvent signal_wait_start( | |
534 base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
535 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
536 base::WaitableEvent wait_done( | |
537 base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
538 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
539 io_thread()->task_runner()->PostTask( | |
540 FROM_HERE, base::Bind(&WaitOnIOThread, &signal_wait_start, &wait_done)); | |
541 signal_wait_start.Wait(); | |
542 // |baseline_context_getter| should have only one reference from local | |
543 // variable. | |
544 EXPECT_TRUE(baseline_context_getter->HasOneRef()); | |
545 baseline_context_getter = NULL; | |
546 | |
547 // Unblock and stop IO thread before sync thread. | |
548 wait_done.Signal(); | |
549 io_thread()->Stop(); | |
550 | |
551 // Unblock and stop sync thread. | |
552 wait_for_shutdown.Signal(); | |
553 sync_thread.Stop(); | |
554 } | |
555 | |
556 // Attempt to release the URLRequestContextGetter before the HttpBridgeFactory | |
557 // is initialized. | |
558 TEST_F(MAYBE_SyncHttpBridgeTest, EarlyAbortFactory) { | |
559 // In a real scenario, the following would happen on many threads. For | |
560 // simplicity, this test uses only one thread. | |
561 | |
562 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter( | |
563 new net::TestURLRequestContextGetter(io_thread()->task_runner())); | |
564 CancelationSignal release_request_context_signal; | |
565 | |
566 // UI Thread: Initialize the HttpBridgeFactory. The next step would be to | |
567 // post a task to SBH::Core to have it initialized. | |
568 std::unique_ptr<syncer::HttpBridgeFactory> factory(new HttpBridgeFactory( | |
569 baseline_context_getter.get(), NetworkTimeUpdateCallback(), | |
570 &release_request_context_signal)); | |
571 | |
572 // UI Thread: A very early shutdown request arrives and executes on the UI | |
573 // thread before the posted sync thread task is run. | |
574 release_request_context_signal.Signal(); | |
575 | |
576 // Sync thread: Finally run the posted task, only to find that our | |
577 // HttpBridgeFactory has been neutered. Should not crash. | |
578 factory->Init("TestUserAgent", BindToTrackerCallback()); | |
579 | |
580 // At this point, attempting to use the factory would trigger a crash. Both | |
581 // this test and the real world code should make sure this never happens. | |
582 } | |
583 | |
584 } // namespace syncer | |
OLD | NEW |