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