Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / sync / internal_api / http_bridge_unittest.cc
blob4ab93fd509adcbfab2f1b649e4f5c62c744688a0
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/strings/stringprintf.h"
6 #include "base/synchronization/waitable_event.h"
7 #include "base/threading/thread.h"
8 #include "net/http/http_response_headers.h"
9 #include "net/test/spawned_test_server/spawned_test_server.h"
10 #include "net/url_request/test_url_fetcher_factory.h"
11 #include "net/url_request/url_fetcher_delegate.h"
12 #include "net/url_request/url_request_test_util.h"
13 #include "sync/internal_api/public/base/cancelation_signal.h"
14 #include "sync/internal_api/public/http_bridge.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 namespace syncer {
19 namespace {
20 // TODO(timsteele): Should use PathService here. See Chromium Issue 3113.
21 const base::FilePath::CharType kDocRoot[] =
22 FILE_PATH_LITERAL("chrome/test/data");
25 const char kUserAgent[] = "user-agent";
27 class SyncHttpBridgeTest : public testing::Test {
28 public:
29 SyncHttpBridgeTest()
30 : test_server_(net::SpawnedTestServer::TYPE_HTTP,
31 net::SpawnedTestServer::kLocalhost,
32 base::FilePath(kDocRoot)),
33 fake_default_request_context_getter_(NULL),
34 bridge_for_race_test_(NULL),
35 io_thread_("IO thread") {
38 void SetUp() override {
39 base::Thread::Options options;
40 options.message_loop_type = base::MessageLoop::TYPE_IO;
41 io_thread_.StartWithOptions(options);
44 void TearDown() override {
45 if (fake_default_request_context_getter_) {
46 GetIOThreadLoop()->ReleaseSoon(FROM_HERE,
47 fake_default_request_context_getter_);
48 fake_default_request_context_getter_ = NULL;
50 io_thread_.Stop();
53 HttpBridge* BuildBridge() {
54 if (!fake_default_request_context_getter_) {
55 fake_default_request_context_getter_ =
56 new net::TestURLRequestContextGetter(io_thread_.message_loop_proxy());
57 fake_default_request_context_getter_->AddRef();
59 HttpBridge* bridge =
60 new HttpBridge(kUserAgent,
61 fake_default_request_context_getter_,
62 NetworkTimeUpdateCallback());
63 return bridge;
66 static void Abort(HttpBridge* bridge) {
67 bridge->Abort();
70 // Used by AbortAndReleaseBeforeFetchCompletes to test an interesting race
71 // condition.
72 void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created,
73 base::WaitableEvent* signal_when_released);
75 static void TestSameHttpNetworkSession(base::MessageLoop* main_message_loop,
76 SyncHttpBridgeTest* test) {
77 scoped_refptr<HttpBridge> http_bridge(test->BuildBridge());
78 EXPECT_TRUE(test->GetTestRequestContextGetter());
79 net::HttpNetworkSession* test_session =
80 test->GetTestRequestContextGetter()->GetURLRequestContext()->
81 http_transaction_factory()->GetSession();
82 EXPECT_EQ(test_session,
83 http_bridge->GetRequestContextGetterForTest()->
84 GetURLRequestContext()->
85 http_transaction_factory()->GetSession());
86 main_message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
89 base::MessageLoop* GetIOThreadLoop() { return io_thread_.message_loop(); }
91 // Note this is lazy created, so don't call this before your bridge.
92 net::TestURLRequestContextGetter* GetTestRequestContextGetter() {
93 return fake_default_request_context_getter_;
96 net::SpawnedTestServer test_server_;
98 base::Thread* io_thread() { return &io_thread_; }
100 HttpBridge* bridge_for_race_test() { return bridge_for_race_test_; }
102 private:
103 // A make-believe "default" request context, as would be returned by
104 // Profile::GetDefaultRequestContext(). Created lazily by BuildBridge.
105 net::TestURLRequestContextGetter* fake_default_request_context_getter_;
107 HttpBridge* bridge_for_race_test_;
109 // Separate thread for IO used by the HttpBridge.
110 base::Thread io_thread_;
111 base::MessageLoop loop_;
114 // An HttpBridge that doesn't actually make network requests and just calls
115 // back with dummy response info.
116 // TODO(tim): Instead of inheriting here we should inject a component
117 // responsible for the MakeAsynchronousPost bit.
118 class ShuntedHttpBridge : public HttpBridge {
119 public:
120 // If |never_finishes| is true, the simulated request never actually
121 // returns.
122 ShuntedHttpBridge(net::URLRequestContextGetter* baseline_context_getter,
123 SyncHttpBridgeTest* test, bool never_finishes)
124 : HttpBridge(kUserAgent,
125 baseline_context_getter,
126 NetworkTimeUpdateCallback()),
127 test_(test), never_finishes_(never_finishes) { }
128 protected:
129 void MakeAsynchronousPost() override {
130 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
131 if (never_finishes_)
132 return;
134 // We don't actually want to make a request for this test, so just callback
135 // as if it completed.
136 test_->GetIOThreadLoop()->PostTask(FROM_HERE,
137 base::Bind(&ShuntedHttpBridge::CallOnURLFetchComplete, this));
139 private:
140 ~ShuntedHttpBridge() override {}
142 void CallOnURLFetchComplete() {
143 ASSERT_TRUE(base::MessageLoop::current() == test_->GetIOThreadLoop());
144 // We return no cookies and a dummy content response.
145 net::ResponseCookies cookies;
147 std::string response_content = "success!";
148 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL);
149 fetcher.set_response_code(200);
150 fetcher.set_cookies(cookies);
151 fetcher.SetResponseString(response_content);
152 OnURLFetchComplete(&fetcher);
154 SyncHttpBridgeTest* test_;
155 bool never_finishes_;
158 void SyncHttpBridgeTest::RunSyncThreadBridgeUseTest(
159 base::WaitableEvent* signal_when_created,
160 base::WaitableEvent* signal_when_released) {
161 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
162 new net::TestURLRequestContextGetter(io_thread_.message_loop_proxy()));
164 scoped_refptr<ShuntedHttpBridge> bridge(
165 new ShuntedHttpBridge(ctx_getter.get(), this, true));
166 bridge->SetURL("http://www.google.com", 9999);
167 bridge->SetPostPayload("text/plain", 2, " ");
168 bridge_for_race_test_ = bridge.get();
169 signal_when_created->Signal();
171 int os_error = 0;
172 int response_code = 0;
173 bridge->MakeSynchronousPost(&os_error, &response_code);
174 bridge_for_race_test_ = NULL;
176 signal_when_released->Signal();
179 TEST_F(SyncHttpBridgeTest, TestUsesSameHttpNetworkSession) {
180 // Run this test on the IO thread because we can only call
181 // URLRequestContextGetter::GetURLRequestContext on the IO thread.
182 io_thread()->message_loop()
183 ->PostTask(FROM_HERE,
184 base::Bind(&SyncHttpBridgeTest::TestSameHttpNetworkSession,
185 base::MessageLoop::current(),
186 this));
187 base::MessageLoop::current()->Run();
190 // Test the HttpBridge without actually making any network requests.
191 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostShunted) {
192 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
193 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
194 scoped_refptr<HttpBridge> http_bridge(
195 new ShuntedHttpBridge(ctx_getter.get(), this, false));
196 http_bridge->SetURL("http://www.google.com", 9999);
197 http_bridge->SetPostPayload("text/plain", 2, " ");
199 int os_error = 0;
200 int response_code = 0;
201 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
202 EXPECT_TRUE(success);
203 EXPECT_EQ(200, response_code);
204 EXPECT_EQ(0, os_error);
206 EXPECT_EQ(8, http_bridge->GetResponseContentLength());
207 EXPECT_EQ(std::string("success!"),
208 std::string(http_bridge->GetResponseContent()));
211 // Full round-trip test of the HttpBridge, using default UA string and
212 // no request cookies.
213 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveWithPayload) {
214 ASSERT_TRUE(test_server_.Start());
216 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
218 std::string payload = "this should be echoed back";
219 GURL echo = test_server_.GetURL("echo");
220 http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
221 http_bridge->SetPostPayload("application/x-www-form-urlencoded",
222 payload.length() + 1, payload.c_str());
223 int os_error = 0;
224 int response_code = 0;
225 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
226 EXPECT_TRUE(success);
227 EXPECT_EQ(200, response_code);
228 EXPECT_EQ(0, os_error);
230 EXPECT_EQ(payload.length() + 1,
231 static_cast<size_t>(http_bridge->GetResponseContentLength()));
232 EXPECT_EQ(payload, std::string(http_bridge->GetResponseContent()));
235 // Full round-trip test of the HttpBridge.
236 TEST_F(SyncHttpBridgeTest, TestMakeSynchronousPostLiveComprehensive) {
237 ASSERT_TRUE(test_server_.Start());
239 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
241 GURL echo_header = test_server_.GetURL("echoall");
242 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
244 std::string test_payload = "###TEST PAYLOAD###";
245 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
246 test_payload.c_str());
248 int os_error = 0;
249 int response_code = 0;
250 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
251 EXPECT_TRUE(success);
252 EXPECT_EQ(200, response_code);
253 EXPECT_EQ(0, os_error);
255 std::string response(http_bridge->GetResponseContent(),
256 http_bridge->GetResponseContentLength());
257 EXPECT_EQ(std::string::npos, response.find("Cookie:"));
258 EXPECT_NE(std::string::npos,
259 response.find(base::StringPrintf("%s: %s",
260 net::HttpRequestHeaders::kUserAgent, kUserAgent)));
261 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
264 TEST_F(SyncHttpBridgeTest, TestExtraRequestHeaders) {
265 ASSERT_TRUE(test_server_.Start());
267 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
269 GURL echo_header = test_server_.GetURL("echoall");
271 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
272 http_bridge->SetExtraRequestHeaders("test:fnord");
274 std::string test_payload = "###TEST PAYLOAD###";
275 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
276 test_payload.c_str());
278 int os_error = 0;
279 int response_code = 0;
280 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
281 EXPECT_TRUE(success);
282 EXPECT_EQ(200, response_code);
283 EXPECT_EQ(0, os_error);
285 std::string response(http_bridge->GetResponseContent(),
286 http_bridge->GetResponseContentLength());
288 EXPECT_NE(std::string::npos, response.find("fnord"));
289 EXPECT_NE(std::string::npos, response.find(test_payload.c_str()));
292 TEST_F(SyncHttpBridgeTest, TestResponseHeader) {
293 ASSERT_TRUE(test_server_.Start());
295 scoped_refptr<HttpBridge> http_bridge(BuildBridge());
297 GURL echo_header = test_server_.GetURL("echoall");
298 http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
300 std::string test_payload = "###TEST PAYLOAD###";
301 http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
302 test_payload.c_str());
304 int os_error = 0;
305 int response_code = 0;
306 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
307 EXPECT_TRUE(success);
308 EXPECT_EQ(200, response_code);
309 EXPECT_EQ(0, os_error);
311 EXPECT_EQ(http_bridge->GetResponseHeaderValue("Content-type"), "text/html");
312 EXPECT_TRUE(http_bridge->GetResponseHeaderValue("invalid-header").empty());
315 TEST_F(SyncHttpBridgeTest, Abort) {
316 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
317 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
318 scoped_refptr<ShuntedHttpBridge> http_bridge(
319 new ShuntedHttpBridge(ctx_getter.get(), this, true));
320 http_bridge->SetURL("http://www.google.com", 9999);
321 http_bridge->SetPostPayload("text/plain", 2, " ");
323 int os_error = 0;
324 int response_code = 0;
326 io_thread()->message_loop_proxy()->PostTask(
327 FROM_HERE,
328 base::Bind(&SyncHttpBridgeTest::Abort, http_bridge));
329 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
330 EXPECT_FALSE(success);
331 EXPECT_EQ(net::ERR_ABORTED, os_error);
334 TEST_F(SyncHttpBridgeTest, AbortLate) {
335 scoped_refptr<net::URLRequestContextGetter> ctx_getter(
336 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
337 scoped_refptr<ShuntedHttpBridge> http_bridge(
338 new ShuntedHttpBridge(ctx_getter.get(), this, false));
339 http_bridge->SetURL("http://www.google.com", 9999);
340 http_bridge->SetPostPayload("text/plain", 2, " ");
342 int os_error = 0;
343 int response_code = 0;
345 bool success = http_bridge->MakeSynchronousPost(&os_error, &response_code);
346 ASSERT_TRUE(success);
347 http_bridge->Abort();
348 // Ensures no double-free of URLFetcher, etc.
351 // Tests an interesting case where code using the HttpBridge aborts the fetch
352 // and releases ownership before a pending fetch completed callback is issued by
353 // the underlying URLFetcher (and before that URLFetcher is destroyed, which
354 // would cancel the callback).
355 TEST_F(SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) {
356 base::Thread sync_thread("SyncThread");
357 sync_thread.Start();
359 // First, block the sync thread on the post.
360 base::WaitableEvent signal_when_created(false, false);
361 base::WaitableEvent signal_when_released(false, false);
362 sync_thread.message_loop()->PostTask(FROM_HERE,
363 base::Bind(&SyncHttpBridgeTest::RunSyncThreadBridgeUseTest,
364 base::Unretained(this),
365 &signal_when_created,
366 &signal_when_released));
368 // Stop IO so we can control order of operations.
369 base::WaitableEvent io_waiter(false, false);
370 ASSERT_TRUE(io_thread()->message_loop_proxy()->PostTask(
371 FROM_HERE,
372 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&io_waiter))));
374 signal_when_created.Wait(); // Wait till we have a bridge to abort.
375 ASSERT_TRUE(bridge_for_race_test());
377 // Schedule the fetch completion callback (but don't run it yet). Don't take
378 // a reference to the bridge to mimic URLFetcher's handling of the delegate.
379 net::URLFetcherDelegate* delegate =
380 static_cast<net::URLFetcherDelegate*>(bridge_for_race_test());
381 net::ResponseCookies cookies;
382 std::string response_content = "success!";
383 net::TestURLFetcher fetcher(0, GURL("http://www.google.com"), NULL);
384 fetcher.set_response_code(200);
385 fetcher.set_cookies(cookies);
386 fetcher.SetResponseString(response_content);
387 ASSERT_TRUE(io_thread()->message_loop_proxy()->PostTask(
388 FROM_HERE,
389 base::Bind(&net::URLFetcherDelegate::OnURLFetchComplete,
390 base::Unretained(delegate), &fetcher)));
392 // Abort the fetch. This should be smart enough to handle the case where
393 // the bridge is destroyed before the callback scheduled above completes.
394 bridge_for_race_test()->Abort();
396 // Wait until the sync thread releases its ref on the bridge.
397 signal_when_released.Wait();
398 ASSERT_FALSE(bridge_for_race_test());
400 // Unleash the hounds. The fetch completion callback should fire first, and
401 // succeed even though we Release()d the bridge above because the call to
402 // Abort should have held a reference.
403 io_waiter.Signal();
405 // Done.
406 sync_thread.Stop();
407 io_thread()->Stop();
410 void HttpBridgeRunOnSyncThread(
411 net::URLRequestContextGetter* baseline_context_getter,
412 CancelationSignal* factory_cancelation_signal,
413 syncer::HttpPostProviderFactory** bridge_factory_out,
414 syncer::HttpPostProviderInterface** bridge_out,
415 base::WaitableEvent* signal_when_created,
416 base::WaitableEvent* wait_for_shutdown) {
417 scoped_ptr<syncer::HttpBridgeFactory> bridge_factory(
418 new syncer::HttpBridgeFactory(baseline_context_getter,
419 NetworkTimeUpdateCallback(),
420 factory_cancelation_signal));
421 bridge_factory->Init("test");
422 *bridge_factory_out = bridge_factory.get();
424 HttpPostProviderInterface* bridge = bridge_factory->Create();
425 *bridge_out = bridge;
427 signal_when_created->Signal();
428 wait_for_shutdown->Wait();
430 bridge_factory->Destroy(bridge);
433 void WaitOnIOThread(base::WaitableEvent* signal_wait_start,
434 base::WaitableEvent* wait_done) {
435 signal_wait_start->Signal();
436 wait_done->Wait();
439 // Tests RequestContextGetter is properly released on IO thread even when
440 // IO thread stops before sync thread.
441 TEST_F(SyncHttpBridgeTest, RequestContextGetterReleaseOrder) {
442 base::Thread sync_thread("SyncThread");
443 sync_thread.Start();
445 syncer::HttpPostProviderFactory* factory = NULL;
446 syncer::HttpPostProviderInterface* bridge = NULL;
448 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
449 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
451 base::WaitableEvent signal_when_created(false, false);
452 base::WaitableEvent wait_for_shutdown(false, false);
454 CancelationSignal release_request_context_signal;
456 // Create bridge factory and factory on sync thread and wait for the creation
457 // to finish.
458 sync_thread.message_loop()->PostTask(FROM_HERE,
459 base::Bind(&HttpBridgeRunOnSyncThread,
460 base::Unretained(baseline_context_getter.get()),
461 &release_request_context_signal ,&factory, &bridge,
462 &signal_when_created, &wait_for_shutdown));
463 signal_when_created.Wait();
465 // Simulate sync shutdown by aborting bridge and shutting down factory on
466 // frontend.
467 bridge->Abort();
468 release_request_context_signal.Signal();
470 // Wait for sync's RequestContextGetter to be cleared on IO thread and
471 // check for reference count.
472 base::WaitableEvent signal_wait_start(false, false);
473 base::WaitableEvent wait_done(false, false);
474 io_thread()->message_loop()->PostTask(
475 FROM_HERE,
476 base::Bind(&WaitOnIOThread, &signal_wait_start, &wait_done));
477 signal_wait_start.Wait();
478 // |baseline_context_getter| should have only one reference from local
479 // variable.
480 EXPECT_TRUE(baseline_context_getter->HasOneRef());
481 baseline_context_getter = NULL;
483 // Unblock and stop IO thread before sync thread.
484 wait_done.Signal();
485 io_thread()->Stop();
487 // Unblock and stop sync thread.
488 wait_for_shutdown.Signal();
489 sync_thread.Stop();
492 // Attempt to release the URLRequestContextGetter before the HttpBridgeFactory
493 // is initialized.
494 TEST_F(SyncHttpBridgeTest, EarlyAbortFactory) {
495 // In a real scenario, the following would happen on many threads. For
496 // simplicity, this test uses only one thread.
498 scoped_refptr<net::URLRequestContextGetter> baseline_context_getter(
499 new net::TestURLRequestContextGetter(io_thread()->message_loop_proxy()));
500 CancelationSignal release_request_context_signal;
502 // UI Thread: Initialize the HttpBridgeFactory. The next step would be to
503 // post a task to SBH::Core to have it initialized.
504 scoped_ptr<syncer::HttpBridgeFactory> factory(
505 new HttpBridgeFactory(baseline_context_getter.get(),
506 NetworkTimeUpdateCallback(),
507 &release_request_context_signal));
509 // UI Thread: A very early shutdown request arrives and executes on the UI
510 // thread before the posted sync thread task is run.
511 release_request_context_signal.Signal();
513 // Sync thread: Finally run the posted task, only to find that our
514 // HttpBridgeFactory has been neutered. Should not crash.
515 factory->Init("TestUserAgent");
517 // At this point, attempting to use the factory would trigger a crash. Both
518 // this test and the real world code should make sure this never happens.
521 } // namespace syncer