Vectorize website settings icons in omnibox
[chromium-blink-merge.git] / components / invalidation / impl / gcm_network_channel_unittest.cc
blobe07788e5e0d5d88a35f7ec9795d791b60b252899
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_split.h"
7 #include "base/strings/string_util.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "components/invalidation/impl/gcm_network_channel.h"
10 #include "google_apis/gaia/google_service_auth_error.h"
11 #include "net/url_request/test_url_fetcher_factory.h"
12 #include "net/url_request/url_request_test_util.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 namespace syncer {
17 class TestGCMNetworkChannelDelegate : public GCMNetworkChannelDelegate {
18 public:
19 TestGCMNetworkChannelDelegate()
20 : register_call_count_(0) {}
22 void Initialize(
23 GCMNetworkChannelDelegate::ConnectionStateCallback callback) override {
24 connection_state_callback = callback;
27 void RequestToken(RequestTokenCallback callback) override {
28 request_token_callback = callback;
31 void InvalidateToken(const std::string& token) override {
32 invalidated_token = token;
35 void Register(RegisterCallback callback) override {
36 ++register_call_count_;
37 register_callback = callback;
40 void SetMessageReceiver(MessageCallback callback) override {
41 message_callback = callback;
44 RequestTokenCallback request_token_callback;
45 std::string invalidated_token;
46 RegisterCallback register_callback;
47 int register_call_count_;
48 MessageCallback message_callback;
49 ConnectionStateCallback connection_state_callback;
52 // Backoff policy for test. Run first 5 retries without delay.
53 const net::BackoffEntry::Policy kTestBackoffPolicy = {
54 // Number of initial errors (in sequence) to ignore before applying
55 // exponential back-off rules.
58 // Initial delay for exponential back-off in ms.
59 2000, // 2 seconds.
61 // Factor by which the waiting time will be multiplied.
64 // Fuzzing percentage. ex: 10% will spread requests randomly
65 // between 90%-100% of the calculated time.
66 0.2, // 20%.
68 // Maximum amount of time we are willing to delay our request in ms.
69 1000 * 3600 * 4, // 4 hours.
71 // Time to keep an entry from being discarded even when it
72 // has no significant state, -1 to never discard.
73 -1,
75 // Don't use initial delay unless the last request was an error.
76 false,
79 class TestGCMNetworkChannel : public GCMNetworkChannel {
80 public:
81 TestGCMNetworkChannel(
82 scoped_refptr<net::URLRequestContextGetter> request_context_getter,
83 scoped_ptr<GCMNetworkChannelDelegate> delegate)
84 : GCMNetworkChannel(request_context_getter, delegate.Pass()) {
85 ResetRegisterBackoffEntryForTest(&kTestBackoffPolicy);
88 protected:
89 // On Android GCMNetworkChannel::BuildUrl hits NOTREACHED(). I still want
90 // tests to run.
91 GURL BuildUrl(const std::string& registration_id) override {
92 return GURL("http://test.url.com");
96 class GCMNetworkChannelTest;
98 // Test needs to capture setting echo-token header on http request.
99 // This class is going to do that.
100 class TestNetworkChannelURLFetcher : public net::FakeURLFetcher {
101 public:
102 TestNetworkChannelURLFetcher(GCMNetworkChannelTest* test,
103 const GURL& url,
104 net::URLFetcherDelegate* delegate,
105 const std::string& response_data,
106 net::HttpStatusCode response_code,
107 net::URLRequestStatus::Status status)
108 : net::FakeURLFetcher(url,
109 delegate,
110 response_data,
111 response_code,
112 status),
113 test_(test) {}
115 void AddExtraRequestHeader(const std::string& header_line) override;
117 private:
118 GCMNetworkChannelTest* test_;
121 class GCMNetworkChannelTest
122 : public ::testing::Test,
123 public SyncNetworkChannel::Observer {
124 public:
125 GCMNetworkChannelTest()
126 : delegate_(NULL),
127 url_fetchers_created_count_(0),
128 last_invalidator_state_(TRANSIENT_INVALIDATION_ERROR) {}
130 ~GCMNetworkChannelTest() override {}
132 void SetUp() override {
133 request_context_getter_ = new net::TestURLRequestContextGetter(
134 base::ThreadTaskRunnerHandle::Get());
135 // Ownership of delegate goes to GCNMentworkChannel but test needs pointer
136 // to it.
137 delegate_ = new TestGCMNetworkChannelDelegate();
138 scoped_ptr<GCMNetworkChannelDelegate> delegate(delegate_);
139 gcm_network_channel_.reset(new TestGCMNetworkChannel(
140 request_context_getter_,
141 delegate.Pass()));
142 gcm_network_channel_->AddObserver(this);
143 gcm_network_channel_->SetMessageReceiver(
144 invalidation::NewPermanentCallback(
145 this, &GCMNetworkChannelTest::OnIncomingMessage));
146 url_fetcher_factory_.reset(new net::FakeURLFetcherFactory(NULL,
147 base::Bind(&GCMNetworkChannelTest::CreateURLFetcher,
148 base::Unretained(this))));
151 void TearDown() override { gcm_network_channel_->RemoveObserver(this); }
153 // Helper functions to call private methods from test
154 GURL BuildUrl(const std::string& registration_id) {
155 return gcm_network_channel_->GCMNetworkChannel::BuildUrl(registration_id);
158 static void Base64EncodeURLSafe(const std::string& input,
159 std::string* output) {
160 GCMNetworkChannel::Base64EncodeURLSafe(input, output);
163 static bool Base64DecodeURLSafe(const std::string& input,
164 std::string* output) {
165 return GCMNetworkChannel::Base64DecodeURLSafe(input, output);
168 void OnNetworkChannelStateChanged(
169 InvalidatorState invalidator_state) override {
170 last_invalidator_state_ = invalidator_state;
173 void OnIncomingMessage(std::string incoming_message) {
176 GCMNetworkChannel* network_channel() {
177 return gcm_network_channel_.get();
180 TestGCMNetworkChannelDelegate* delegate() {
181 return delegate_;
184 int url_fetchers_created_count() {
185 return url_fetchers_created_count_;
188 net::FakeURLFetcherFactory* url_fetcher_factory() {
189 return url_fetcher_factory_.get();
192 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
193 const GURL& url,
194 net::URLFetcherDelegate* delegate,
195 const std::string& response_data,
196 net::HttpStatusCode response_code,
197 net::URLRequestStatus::Status status) {
198 ++url_fetchers_created_count_;
199 return scoped_ptr<net::FakeURLFetcher>(new TestNetworkChannelURLFetcher(
200 this, url, delegate, response_data, response_code, status));
203 void set_last_echo_token(const std::string& echo_token) {
204 last_echo_token_ = echo_token;
207 const std::string& get_last_echo_token() {
208 return last_echo_token_;
211 InvalidatorState get_last_invalidator_state() {
212 return last_invalidator_state_;
215 void RunLoopUntilIdle() {
216 base::RunLoop run_loop;
217 run_loop.RunUntilIdle();
220 private:
221 base::MessageLoop message_loop_;
222 TestGCMNetworkChannelDelegate* delegate_;
223 scoped_ptr<GCMNetworkChannel> gcm_network_channel_;
224 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
225 scoped_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_;
226 int url_fetchers_created_count_;
227 std::string last_echo_token_;
228 InvalidatorState last_invalidator_state_;
231 void TestNetworkChannelURLFetcher::AddExtraRequestHeader(
232 const std::string& header_line) {
233 net::FakeURLFetcher::AddExtraRequestHeader(header_line);
234 std::string header_name("echo-token: ");
235 std::string echo_token;
236 if (base::StartsWith(header_line, header_name,
237 base::CompareCase::INSENSITIVE_ASCII)) {
238 echo_token = header_line;
239 base::ReplaceFirstSubstringAfterOffset(
240 &echo_token, 0, header_name, std::string());
241 test_->set_last_echo_token(echo_token);
245 TEST_F(GCMNetworkChannelTest, HappyCase) {
246 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
247 EXPECT_FALSE(delegate()->message_callback.is_null());
248 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
249 std::string(),
250 net::HTTP_NO_CONTENT,
251 net::URLRequestStatus::SUCCESS);
253 // Emulate gcm connection state to be online.
254 delegate()->connection_state_callback.Run(true);
255 // After construction GCMNetworkChannel should have called Register.
256 EXPECT_FALSE(delegate()->register_callback.is_null());
257 // Return valid registration id.
258 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
260 network_channel()->SendMessage("abra.cadabra");
261 // SendMessage should have triggered RequestToken. No HTTP request should be
262 // started yet.
263 EXPECT_FALSE(delegate()->request_token_callback.is_null());
264 EXPECT_EQ(url_fetchers_created_count(), 0);
265 // Return valid access token. This should trigger HTTP request.
266 delegate()->request_token_callback.Run(
267 GoogleServiceAuthError::AuthErrorNone(), "access.token");
268 RunLoopUntilIdle();
269 EXPECT_EQ(url_fetchers_created_count(), 1);
271 // Return another access token. Message should be cleared by now and shouldn't
272 // be sent.
273 delegate()->request_token_callback.Run(
274 GoogleServiceAuthError::AuthErrorNone(), "access.token2");
275 RunLoopUntilIdle();
276 EXPECT_EQ(url_fetchers_created_count(), 1);
277 EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
280 TEST_F(GCMNetworkChannelTest, FailedRegister) {
281 // After construction GCMNetworkChannel should have called Register.
282 EXPECT_FALSE(delegate()->register_callback.is_null());
283 EXPECT_EQ(1, delegate()->register_call_count_);
284 // Return transient error from Register call.
285 delegate()->register_callback.Run("", gcm::GCMClient::NETWORK_ERROR);
286 RunLoopUntilIdle();
287 // GcmNetworkChannel should have scheduled Register retry.
288 EXPECT_EQ(2, delegate()->register_call_count_);
289 // Return persistent error from Register call.
290 delegate()->register_callback.Run("", gcm::GCMClient::GCM_DISABLED);
291 RunLoopUntilIdle();
292 // GcmNetworkChannel should give up trying.
293 EXPECT_EQ(2, delegate()->register_call_count_);
295 network_channel()->SendMessage("abra.cadabra");
296 // SendMessage shouldn't trigger RequestToken.
297 EXPECT_TRUE(delegate()->request_token_callback.is_null());
298 EXPECT_EQ(0, url_fetchers_created_count());
301 TEST_F(GCMNetworkChannelTest, RegisterFinishesAfterSendMessage) {
302 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
304 net::HTTP_NO_CONTENT,
305 net::URLRequestStatus::SUCCESS);
307 // After construction GCMNetworkChannel should have called Register.
308 EXPECT_FALSE(delegate()->register_callback.is_null());
310 network_channel()->SendMessage("abra.cadabra");
311 // SendMessage shouldn't trigger RequestToken.
312 EXPECT_TRUE(delegate()->request_token_callback.is_null());
313 EXPECT_EQ(url_fetchers_created_count(), 0);
315 // Return valid registration id.
316 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
318 EXPECT_FALSE(delegate()->request_token_callback.is_null());
319 EXPECT_EQ(url_fetchers_created_count(), 0);
320 // Return valid access token. This should trigger HTTP request.
321 delegate()->request_token_callback.Run(
322 GoogleServiceAuthError::AuthErrorNone(), "access.token");
323 RunLoopUntilIdle();
324 EXPECT_EQ(url_fetchers_created_count(), 1);
327 TEST_F(GCMNetworkChannelTest, RequestTokenFailure) {
328 // After construction GCMNetworkChannel should have called Register.
329 EXPECT_FALSE(delegate()->register_callback.is_null());
330 // Return valid registration id.
331 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
333 network_channel()->SendMessage("abra.cadabra");
334 // SendMessage should have triggered RequestToken. No HTTP request should be
335 // started yet.
336 EXPECT_FALSE(delegate()->request_token_callback.is_null());
337 EXPECT_EQ(url_fetchers_created_count(), 0);
338 // RequestToken returns failure.
339 delegate()->request_token_callback.Run(
340 GoogleServiceAuthError::FromConnectionError(1), "");
342 // Should be no HTTP requests.
343 EXPECT_EQ(url_fetchers_created_count(), 0);
346 TEST_F(GCMNetworkChannelTest, AuthErrorFromServer) {
347 // Setup fake response to return AUTH_ERROR.
348 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
350 net::HTTP_UNAUTHORIZED,
351 net::URLRequestStatus::SUCCESS);
353 // After construction GCMNetworkChannel should have called Register.
354 EXPECT_FALSE(delegate()->register_callback.is_null());
355 // Return valid registration id.
356 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
358 network_channel()->SendMessage("abra.cadabra");
359 // SendMessage should have triggered RequestToken. No HTTP request should be
360 // started yet.
361 EXPECT_FALSE(delegate()->request_token_callback.is_null());
362 EXPECT_EQ(url_fetchers_created_count(), 0);
363 // Return valid access token. This should trigger HTTP request.
364 delegate()->request_token_callback.Run(
365 GoogleServiceAuthError::AuthErrorNone(), "access.token");
366 RunLoopUntilIdle();
367 EXPECT_EQ(url_fetchers_created_count(), 1);
368 EXPECT_EQ(delegate()->invalidated_token, "access.token");
371 // Following two tests are to check for memory leaks/crashes when Register and
372 // RequestToken don't complete by the teardown.
373 TEST_F(GCMNetworkChannelTest, RegisterNeverCompletes) {
374 network_channel()->SendMessage("abra.cadabra");
375 // Register should be called by now. Let's not complete and see what happens.
376 EXPECT_FALSE(delegate()->register_callback.is_null());
379 TEST_F(GCMNetworkChannelTest, RequestTokenNeverCompletes) {
380 network_channel()->SendMessage("abra.cadabra");
381 // Return valid registration id.
382 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
383 // RequestToken should be called by now. Let's not complete and see what
384 // happens.
385 EXPECT_FALSE(delegate()->request_token_callback.is_null());
388 TEST_F(GCMNetworkChannelTest, Base64EncodeDecode) {
389 std::string input;
390 std::string plain;
391 std::string base64;
392 // Empty string.
393 Base64EncodeURLSafe(input, &base64);
394 EXPECT_TRUE(base64.empty());
395 EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
396 EXPECT_EQ(input, plain);
397 // String length: 1..7.
398 for (int length = 1; length < 8; length++) {
399 input = "abra.cadabra";
400 input.resize(length);
401 Base64EncodeURLSafe(input, &base64);
402 // Ensure no padding at the end.
403 EXPECT_NE(base64[base64.size() - 1], '=');
404 EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
405 EXPECT_EQ(input, plain);
407 // Presence of '-', '_'.
408 input = "\xfb\xff";
409 Base64EncodeURLSafe(input, &base64);
410 EXPECT_EQ("-_8", base64);
411 EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
412 EXPECT_EQ(input, plain);
415 TEST_F(GCMNetworkChannelTest, ChannelState) {
416 EXPECT_FALSE(delegate()->message_callback.is_null());
417 // POST will fail.
418 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
419 std::string(),
420 net::HTTP_SERVICE_UNAVAILABLE,
421 net::URLRequestStatus::SUCCESS);
423 delegate()->connection_state_callback.Run(true);
424 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
426 network_channel()->SendMessage("abra.cadabra");
427 EXPECT_FALSE(delegate()->request_token_callback.is_null());
428 delegate()->request_token_callback.Run(
429 GoogleServiceAuthError::AuthErrorNone(), "access.token");
430 RunLoopUntilIdle();
431 EXPECT_EQ(url_fetchers_created_count(), 1);
432 // Failing HTTP POST should cause TRANSIENT_INVALIDATION_ERROR.
433 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
435 // Setup POST to succeed.
436 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
438 net::HTTP_NO_CONTENT,
439 net::URLRequestStatus::SUCCESS);
440 network_channel()->SendMessage("abra.cadabra");
441 EXPECT_FALSE(delegate()->request_token_callback.is_null());
442 delegate()->request_token_callback.Run(
443 GoogleServiceAuthError::AuthErrorNone(), "access.token");
444 RunLoopUntilIdle();
445 EXPECT_EQ(url_fetchers_created_count(), 2);
446 // Successful post should set invalidator state to enabled.
447 EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
448 // Network changed event shouldn't affect invalidator state.
449 network_channel()->OnNetworkChanged(
450 net::NetworkChangeNotifier::CONNECTION_NONE);
451 EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
453 // GCM connection state should affect invalidator state.
454 delegate()->connection_state_callback.Run(false);
455 EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
456 delegate()->connection_state_callback.Run(true);
457 EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
460 #if !defined(OS_ANDROID)
461 TEST_F(GCMNetworkChannelTest, BuildUrl) {
462 GURL url = BuildUrl("registration.id");
463 EXPECT_TRUE(url.SchemeIsHTTPOrHTTPS());
464 EXPECT_FALSE(url.host().empty());
465 EXPECT_FALSE(url.path().empty());
466 std::vector<std::string> parts = base::SplitString(
467 url.path(), "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
468 std::string buffer;
469 EXPECT_TRUE(Base64DecodeURLSafe(parts[parts.size() - 1], &buffer));
472 TEST_F(GCMNetworkChannelTest, EchoToken) {
473 url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
474 std::string(),
475 net::HTTP_OK,
476 net::URLRequestStatus::SUCCESS);
477 // After construction GCMNetworkChannel should have called Register.
478 // Return valid registration id.
479 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
481 network_channel()->SendMessage("abra.cadabra");
482 // Return valid access token. This should trigger HTTP request.
483 delegate()->request_token_callback.Run(
484 GoogleServiceAuthError::AuthErrorNone(), "access.token");
485 RunLoopUntilIdle();
486 EXPECT_EQ(url_fetchers_created_count(), 1);
487 EXPECT_TRUE(get_last_echo_token().empty());
489 // Trigger response.
490 delegate()->message_callback.Run("abra.cadabra", "echo.token");
491 // Send another message.
492 network_channel()->SendMessage("abra.cadabra");
493 // Return valid access token. This should trigger HTTP request.
494 delegate()->request_token_callback.Run(
495 GoogleServiceAuthError::AuthErrorNone(), "access.token");
496 RunLoopUntilIdle();
497 EXPECT_EQ(url_fetchers_created_count(), 2);
498 EXPECT_EQ("echo.token", get_last_echo_token());
500 // Trigger response with empty echo token.
501 delegate()->message_callback.Run("abra.cadabra", "");
502 // Send another message.
503 network_channel()->SendMessage("abra.cadabra");
504 // Return valid access token. This should trigger HTTP request.
505 delegate()->request_token_callback.Run(
506 GoogleServiceAuthError::AuthErrorNone(), "access.token");
507 RunLoopUntilIdle();
508 EXPECT_EQ(url_fetchers_created_count(), 3);
509 // Echo_token should be from second message.
510 EXPECT_EQ("echo.token", get_last_echo_token());
512 #endif
514 } // namespace syncer