Forward accessibility events to the automation extension process.
[chromium-blink-merge.git] / components / invalidation / gcm_network_channel_unittest.cc
blob34ab7fabd897a67feba4f47c80c4a1b51a573427
1 // Copyright 2014 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/run_loop.h"
6 #include "base/strings/string_util.h"
7 #include "base/thread_task_runner_handle.h"
8 #include "components/invalidation/gcm_network_channel.h"
9 #include "google_apis/gaia/google_service_auth_error.h"
10 #include "net/url_request/test_url_fetcher_factory.h"
11 #include "net/url_request/url_request_test_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
14 namespace syncer {
16 class TestGCMNetworkChannelDelegate : public GCMNetworkChannelDelegate {
17 public:
18 TestGCMNetworkChannelDelegate()
19 : register_call_count_(0) {}
21 void Initialize(
22 GCMNetworkChannelDelegate::ConnectionStateCallback callback) override {
23 connection_state_callback = callback;
26 void RequestToken(RequestTokenCallback callback) override {
27 request_token_callback = callback;
30 void InvalidateToken(const std::string& token) override {
31 invalidated_token = token;
34 void Register(RegisterCallback callback) override {
35 ++register_call_count_;
36 register_callback = callback;
39 void SetMessageReceiver(MessageCallback callback) override {
40 message_callback = callback;
43 RequestTokenCallback request_token_callback;
44 std::string invalidated_token;
45 RegisterCallback register_callback;
46 int register_call_count_;
47 MessageCallback message_callback;
48 ConnectionStateCallback connection_state_callback;
51 // Backoff policy for test. Run first 5 retries without delay.
52 const net::BackoffEntry::Policy kTestBackoffPolicy = {
53 // Number of initial errors (in sequence) to ignore before applying
54 // exponential back-off rules.
57 // Initial delay for exponential back-off in ms.
58 2000, // 2 seconds.
60 // Factor by which the waiting time will be multiplied.
63 // Fuzzing percentage. ex: 10% will spread requests randomly
64 // between 90%-100% of the calculated time.
65 0.2, // 20%.
67 // Maximum amount of time we are willing to delay our request in ms.
68 1000 * 3600 * 4, // 4 hours.
70 // Time to keep an entry from being discarded even when it
71 // has no significant state, -1 to never discard.
72 -1,
74 // Don't use initial delay unless the last request was an error.
75 false,
78 class TestGCMNetworkChannel : public GCMNetworkChannel {
79 public:
80 TestGCMNetworkChannel(
81 scoped_refptr<net::URLRequestContextGetter> request_context_getter,
82 scoped_ptr<GCMNetworkChannelDelegate> delegate)
83 : GCMNetworkChannel(request_context_getter, delegate.Pass()) {
84 ResetRegisterBackoffEntryForTest(&kTestBackoffPolicy);
87 protected:
88 // On Android GCMNetworkChannel::BuildUrl hits NOTREACHED(). I still want
89 // tests to run.
90 GURL BuildUrl(const std::string& registration_id) override {
91 return GURL("http://test.url.com");
95 class GCMNetworkChannelTest;
97 // Test needs to capture setting echo-token header on http request.
98 // This class is going to do that.
99 class TestNetworkChannelURLFetcher : public net::FakeURLFetcher {
100 public:
101 TestNetworkChannelURLFetcher(GCMNetworkChannelTest* test,
102 const GURL& url,
103 net::URLFetcherDelegate* delegate,
104 const std::string& response_data,
105 net::HttpStatusCode response_code,
106 net::URLRequestStatus::Status status)
107 : net::FakeURLFetcher(url,
108 delegate,
109 response_data,
110 response_code,
111 status),
112 test_(test) {}
114 void AddExtraRequestHeader(const std::string& header_line) override;
116 private:
117 GCMNetworkChannelTest* test_;
120 class GCMNetworkChannelTest
121 : public ::testing::Test,
122 public SyncNetworkChannel::Observer {
123 public:
124 GCMNetworkChannelTest()
125 : delegate_(NULL),
126 url_fetchers_created_count_(0),
127 last_invalidator_state_(TRANSIENT_INVALIDATION_ERROR) {}
129 ~GCMNetworkChannelTest() override {}
131 void SetUp() override {
132 request_context_getter_ = new net::TestURLRequestContextGetter(
133 base::ThreadTaskRunnerHandle::Get());
134 // Ownership of delegate goes to GCNMentworkChannel but test needs pointer
135 // to it.
136 delegate_ = new TestGCMNetworkChannelDelegate();
137 scoped_ptr<GCMNetworkChannelDelegate> delegate(delegate_);
138 gcm_network_channel_.reset(new TestGCMNetworkChannel(
139 request_context_getter_,
140 delegate.Pass()));
141 gcm_network_channel_->AddObserver(this);
142 gcm_network_channel_->SetMessageReceiver(
143 invalidation::NewPermanentCallback(
144 this, &GCMNetworkChannelTest::OnIncomingMessage));
145 url_fetcher_factory_.reset(new net::FakeURLFetcherFactory(NULL,
146 base::Bind(&GCMNetworkChannelTest::CreateURLFetcher,
147 base::Unretained(this))));
150 void TearDown() override { gcm_network_channel_->RemoveObserver(this); }
152 // Helper functions to call private methods from test
153 GURL BuildUrl(const std::string& registration_id) {
154 return gcm_network_channel_->GCMNetworkChannel::BuildUrl(registration_id);
157 static void Base64EncodeURLSafe(const std::string& input,
158 std::string* output) {
159 GCMNetworkChannel::Base64EncodeURLSafe(input, output);
162 static bool Base64DecodeURLSafe(const std::string& input,
163 std::string* output) {
164 return GCMNetworkChannel::Base64DecodeURLSafe(input, output);
167 void OnNetworkChannelStateChanged(
168 InvalidatorState invalidator_state) override {
169 last_invalidator_state_ = invalidator_state;
172 void OnIncomingMessage(std::string incoming_message) {
175 GCMNetworkChannel* network_channel() {
176 return gcm_network_channel_.get();
179 TestGCMNetworkChannelDelegate* delegate() {
180 return delegate_;
183 int url_fetchers_created_count() {
184 return url_fetchers_created_count_;
187 net::FakeURLFetcherFactory* url_fetcher_factory() {
188 return url_fetcher_factory_.get();
191 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
192 const GURL& url,
193 net::URLFetcherDelegate* delegate,
194 const std::string& response_data,
195 net::HttpStatusCode response_code,
196 net::URLRequestStatus::Status status) {
197 ++url_fetchers_created_count_;
198 return scoped_ptr<net::FakeURLFetcher>(new TestNetworkChannelURLFetcher(
199 this, url, delegate, response_data, response_code, status));
202 void set_last_echo_token(const std::string& echo_token) {
203 last_echo_token_ = echo_token;
206 const std::string& get_last_echo_token() {
207 return last_echo_token_;
210 InvalidatorState get_last_invalidator_state() {
211 return last_invalidator_state_;
214 void RunLoopUntilIdle() {
215 base::RunLoop run_loop;
216 run_loop.RunUntilIdle();
219 private:
220 base::MessageLoop message_loop_;
221 TestGCMNetworkChannelDelegate* delegate_;
222 scoped_ptr<GCMNetworkChannel> gcm_network_channel_;
223 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
224 scoped_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_;
225 int url_fetchers_created_count_;
226 std::string last_echo_token_;
227 InvalidatorState last_invalidator_state_;
230 void TestNetworkChannelURLFetcher::AddExtraRequestHeader(
231 const std::string& header_line) {
232 net::FakeURLFetcher::AddExtraRequestHeader(header_line);
233 std::string header_name("echo-token: ");
234 std::string echo_token;
235 if (StartsWithASCII(header_line, header_name, false)) {
236 echo_token = header_line;
237 ReplaceFirstSubstringAfterOffset(
238 &echo_token, 0, header_name, std::string());
239 test_->set_last_echo_token(echo_token);
243 TEST_F(GCMNetworkChannelTest, HappyCase) {
244 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
245 EXPECT_FALSE(delegate()->message_callback.is_null());
246 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
247 std::string(),
248 net::HTTP_NO_CONTENT,
249 net::URLRequestStatus::SUCCESS);
251 // Emulate gcm connection state to be online.
252 delegate()->connection_state_callback.Run(true);
253 // After construction GCMNetworkChannel should have called Register.
254 EXPECT_FALSE(delegate()->register_callback.is_null());
255 // Return valid registration id.
256 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
258 network_channel()->SendMessage("abra.cadabra");
259 // SendMessage should have triggered RequestToken. No HTTP request should be
260 // started yet.
261 EXPECT_FALSE(delegate()->request_token_callback.is_null());
262 EXPECT_EQ(url_fetchers_created_count(), 0);
263 // Return valid access token. This should trigger HTTP request.
264 delegate()->request_token_callback.Run(
265 GoogleServiceAuthError::AuthErrorNone(), "access.token");
266 RunLoopUntilIdle();
267 EXPECT_EQ(url_fetchers_created_count(), 1);
269 // Return another access token. Message should be cleared by now and shouldn't
270 // be sent.
271 delegate()->request_token_callback.Run(
272 GoogleServiceAuthError::AuthErrorNone(), "access.token2");
273 RunLoopUntilIdle();
274 EXPECT_EQ(url_fetchers_created_count(), 1);
275 EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
278 TEST_F(GCMNetworkChannelTest, FailedRegister) {
279 // After construction GCMNetworkChannel should have called Register.
280 EXPECT_FALSE(delegate()->register_callback.is_null());
281 EXPECT_EQ(1, delegate()->register_call_count_);
282 // Return transient error from Register call.
283 delegate()->register_callback.Run("", gcm::GCMClient::NETWORK_ERROR);
284 RunLoopUntilIdle();
285 // GcmNetworkChannel should have scheduled Register retry.
286 EXPECT_EQ(2, delegate()->register_call_count_);
287 // Return persistent error from Register call.
288 delegate()->register_callback.Run("", gcm::GCMClient::GCM_DISABLED);
289 RunLoopUntilIdle();
290 // GcmNetworkChannel should give up trying.
291 EXPECT_EQ(2, delegate()->register_call_count_);
293 network_channel()->SendMessage("abra.cadabra");
294 // SendMessage shouldn't trigger RequestToken.
295 EXPECT_TRUE(delegate()->request_token_callback.is_null());
296 EXPECT_EQ(0, url_fetchers_created_count());
299 TEST_F(GCMNetworkChannelTest, RegisterFinishesAfterSendMessage) {
300 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
302 net::HTTP_NO_CONTENT,
303 net::URLRequestStatus::SUCCESS);
305 // After construction GCMNetworkChannel should have called Register.
306 EXPECT_FALSE(delegate()->register_callback.is_null());
308 network_channel()->SendMessage("abra.cadabra");
309 // SendMessage shouldn't trigger RequestToken.
310 EXPECT_TRUE(delegate()->request_token_callback.is_null());
311 EXPECT_EQ(url_fetchers_created_count(), 0);
313 // Return valid registration id.
314 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
316 EXPECT_FALSE(delegate()->request_token_callback.is_null());
317 EXPECT_EQ(url_fetchers_created_count(), 0);
318 // Return valid access token. This should trigger HTTP request.
319 delegate()->request_token_callback.Run(
320 GoogleServiceAuthError::AuthErrorNone(), "access.token");
321 RunLoopUntilIdle();
322 EXPECT_EQ(url_fetchers_created_count(), 1);
325 TEST_F(GCMNetworkChannelTest, RequestTokenFailure) {
326 // After construction GCMNetworkChannel should have called Register.
327 EXPECT_FALSE(delegate()->register_callback.is_null());
328 // Return valid registration id.
329 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
331 network_channel()->SendMessage("abra.cadabra");
332 // SendMessage should have triggered RequestToken. No HTTP request should be
333 // started yet.
334 EXPECT_FALSE(delegate()->request_token_callback.is_null());
335 EXPECT_EQ(url_fetchers_created_count(), 0);
336 // RequestToken returns failure.
337 delegate()->request_token_callback.Run(
338 GoogleServiceAuthError::FromConnectionError(1), "");
340 // Should be no HTTP requests.
341 EXPECT_EQ(url_fetchers_created_count(), 0);
344 TEST_F(GCMNetworkChannelTest, AuthErrorFromServer) {
345 // Setup fake response to return AUTH_ERROR.
346 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
348 net::HTTP_UNAUTHORIZED,
349 net::URLRequestStatus::SUCCESS);
351 // After construction GCMNetworkChannel should have called Register.
352 EXPECT_FALSE(delegate()->register_callback.is_null());
353 // Return valid registration id.
354 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
356 network_channel()->SendMessage("abra.cadabra");
357 // SendMessage should have triggered RequestToken. No HTTP request should be
358 // started yet.
359 EXPECT_FALSE(delegate()->request_token_callback.is_null());
360 EXPECT_EQ(url_fetchers_created_count(), 0);
361 // Return valid access token. This should trigger HTTP request.
362 delegate()->request_token_callback.Run(
363 GoogleServiceAuthError::AuthErrorNone(), "access.token");
364 RunLoopUntilIdle();
365 EXPECT_EQ(url_fetchers_created_count(), 1);
366 EXPECT_EQ(delegate()->invalidated_token, "access.token");
369 // Following two tests are to check for memory leaks/crashes when Register and
370 // RequestToken don't complete by the teardown.
371 TEST_F(GCMNetworkChannelTest, RegisterNeverCompletes) {
372 network_channel()->SendMessage("abra.cadabra");
373 // Register should be called by now. Let's not complete and see what happens.
374 EXPECT_FALSE(delegate()->register_callback.is_null());
377 TEST_F(GCMNetworkChannelTest, RequestTokenNeverCompletes) {
378 network_channel()->SendMessage("abra.cadabra");
379 // Return valid registration id.
380 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
381 // RequestToken should be called by now. Let's not complete and see what
382 // happens.
383 EXPECT_FALSE(delegate()->request_token_callback.is_null());
386 TEST_F(GCMNetworkChannelTest, Base64EncodeDecode) {
387 std::string input;
388 std::string plain;
389 std::string base64;
390 // Empty string.
391 Base64EncodeURLSafe(input, &base64);
392 EXPECT_TRUE(base64.empty());
393 EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
394 EXPECT_EQ(input, plain);
395 // String length: 1..7.
396 for (int length = 1; length < 8; length++) {
397 input = "abra.cadabra";
398 input.resize(length);
399 Base64EncodeURLSafe(input, &base64);
400 // Ensure no padding at the end.
401 EXPECT_NE(base64[base64.size() - 1], '=');
402 EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
403 EXPECT_EQ(input, plain);
405 // Presence of '-', '_'.
406 input = "\xfb\xff";
407 Base64EncodeURLSafe(input, &base64);
408 EXPECT_EQ("-_8", base64);
409 EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
410 EXPECT_EQ(input, plain);
413 TEST_F(GCMNetworkChannelTest, ChannelState) {
414 EXPECT_FALSE(delegate()->message_callback.is_null());
415 // POST will fail.
416 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
417 std::string(),
418 net::HTTP_SERVICE_UNAVAILABLE,
419 net::URLRequestStatus::SUCCESS);
421 delegate()->connection_state_callback.Run(true);
422 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
424 network_channel()->SendMessage("abra.cadabra");
425 EXPECT_FALSE(delegate()->request_token_callback.is_null());
426 delegate()->request_token_callback.Run(
427 GoogleServiceAuthError::AuthErrorNone(), "access.token");
428 RunLoopUntilIdle();
429 EXPECT_EQ(url_fetchers_created_count(), 1);
430 // Failing HTTP POST should cause TRANSIENT_INVALIDATION_ERROR.
431 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
433 // Setup POST to succeed.
434 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
436 net::HTTP_NO_CONTENT,
437 net::URLRequestStatus::SUCCESS);
438 network_channel()->SendMessage("abra.cadabra");
439 EXPECT_FALSE(delegate()->request_token_callback.is_null());
440 delegate()->request_token_callback.Run(
441 GoogleServiceAuthError::AuthErrorNone(), "access.token");
442 RunLoopUntilIdle();
443 EXPECT_EQ(url_fetchers_created_count(), 2);
444 // Successful post should set invalidator state to enabled.
445 EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
446 // Network changed event shouldn't affect invalidator state.
447 network_channel()->OnNetworkChanged(
448 net::NetworkChangeNotifier::CONNECTION_NONE);
449 EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
451 // GCM connection state should affect invalidator state.
452 delegate()->connection_state_callback.Run(false);
453 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
454 delegate()->connection_state_callback.Run(true);
455 EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
458 #if !defined(OS_ANDROID)
459 TEST_F(GCMNetworkChannelTest, BuildUrl) {
460 GURL url = BuildUrl("registration.id");
461 EXPECT_TRUE(url.SchemeIsHTTPOrHTTPS());
462 EXPECT_FALSE(url.host().empty());
463 EXPECT_FALSE(url.path().empty());
464 std::vector<std::string> parts;
465 Tokenize(url.path(), "/", &parts);
466 std::string buffer;
467 EXPECT_TRUE(Base64DecodeURLSafe(parts[parts.size() - 1], &buffer));
470 TEST_F(GCMNetworkChannelTest, EchoToken) {
471 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
472 std::string(),
473 net::HTTP_OK,
474 net::URLRequestStatus::SUCCESS);
475 // After construction GCMNetworkChannel should have called Register.
476 // Return valid registration id.
477 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
479 network_channel()->SendMessage("abra.cadabra");
480 // Return valid access token. This should trigger HTTP request.
481 delegate()->request_token_callback.Run(
482 GoogleServiceAuthError::AuthErrorNone(), "access.token");
483 RunLoopUntilIdle();
484 EXPECT_EQ(url_fetchers_created_count(), 1);
485 EXPECT_TRUE(get_last_echo_token().empty());
487 // Trigger response.
488 delegate()->message_callback.Run("abra.cadabra", "echo.token");
489 // Send another message.
490 network_channel()->SendMessage("abra.cadabra");
491 // Return valid access token. This should trigger HTTP request.
492 delegate()->request_token_callback.Run(
493 GoogleServiceAuthError::AuthErrorNone(), "access.token");
494 RunLoopUntilIdle();
495 EXPECT_EQ(url_fetchers_created_count(), 2);
496 EXPECT_EQ("echo.token", get_last_echo_token());
498 // Trigger response with empty echo token.
499 delegate()->message_callback.Run("abra.cadabra", "");
500 // Send another message.
501 network_channel()->SendMessage("abra.cadabra");
502 // Return valid access token. This should trigger HTTP request.
503 delegate()->request_token_callback.Run(
504 GoogleServiceAuthError::AuthErrorNone(), "access.token");
505 RunLoopUntilIdle();
506 EXPECT_EQ(url_fetchers_created_count(), 3);
507 // Echo_token should be from second message.
508 EXPECT_EQ("echo.token", get_last_echo_token());
510 #endif
512 } // namespace syncer