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 "google_apis/gaia/google_service_auth_error.h"
7 #include "net/url_request/test_url_fetcher_factory.h"
8 #include "net/url_request/url_request_test_util.h"
9 #include "sync/notifier/gcm_network_channel.h"
10 #include "testing/gtest/include/gtest/gtest.h"
15 class TestGCMNetworkChannelDelegate : public GCMNetworkChannelDelegate {
17 TestGCMNetworkChannelDelegate()
18 : register_call_count_(0) {}
20 virtual void RequestToken(RequestTokenCallback callback) OVERRIDE {
21 request_token_callback = callback;
24 virtual void InvalidateToken(const std::string& token) OVERRIDE {
25 invalidated_token = token;
28 virtual void Register(RegisterCallback callback) OVERRIDE {
29 ++register_call_count_;
30 register_callback = callback;
33 RequestTokenCallback request_token_callback;
34 std::string invalidated_token;
35 RegisterCallback register_callback;
36 int register_call_count_;
39 // Backoff policy for test. Run first 5 retries without delay.
40 const net::BackoffEntry::Policy kTestBackoffPolicy = {
41 // Number of initial errors (in sequence) to ignore before applying
42 // exponential back-off rules.
45 // Initial delay for exponential back-off in ms.
48 // Factor by which the waiting time will be multiplied.
51 // Fuzzing percentage. ex: 10% will spread requests randomly
52 // between 90%-100% of the calculated time.
55 // Maximum amount of time we are willing to delay our request in ms.
56 1000 * 3600 * 4, // 4 hours.
58 // Time to keep an entry from being discarded even when it
59 // has no significant state, -1 to never discard.
62 // Don't use initial delay unless the last request was an error.
66 class TestGCMNetworkChannel : public GCMNetworkChannel {
68 TestGCMNetworkChannel(
69 scoped_refptr<net::URLRequestContextGetter> request_context_getter,
70 scoped_ptr<GCMNetworkChannelDelegate> delegate)
71 : GCMNetworkChannel(request_context_getter, delegate.Pass()) {
72 ResetRegisterBackoffEntryForTest(&kTestBackoffPolicy);
76 class GCMNetworkChannelTest
77 : public ::testing::Test,
78 public SyncNetworkChannel::Observer {
80 GCMNetworkChannelTest()
82 url_fetchers_created_count_(0) {
85 virtual ~GCMNetworkChannelTest() {
88 virtual void SetUp() {
89 request_context_getter_ = new net::TestURLRequestContextGetter(
90 base::MessageLoopProxy::current());
91 // Ownership of delegate goes to GCNMentworkChannel but test needs pointer
93 delegate_ = new TestGCMNetworkChannelDelegate();
94 scoped_ptr<GCMNetworkChannelDelegate> delegate(delegate_);
95 gcm_network_channel_.reset(new TestGCMNetworkChannel(
96 request_context_getter_,
98 gcm_network_channel_->AddObserver(this);
99 gcm_network_channel_->SetMessageReceiver(
100 invalidation::NewPermanentCallback(
101 this, &GCMNetworkChannelTest::OnIncomingMessage));
102 url_fetcher_factory_.reset(new net::FakeURLFetcherFactory(NULL,
103 base::Bind(&GCMNetworkChannelTest::CreateURLFetcher,
104 base::Unretained(this))));
107 virtual void TearDown() {
108 gcm_network_channel_->RemoveObserver(this);
111 virtual void OnNetworkChannelStateChanged(
112 InvalidatorState invalidator_state) OVERRIDE {
115 void OnIncomingMessage(std::string incoming_message) {
118 GCMNetworkChannel* network_channel() {
119 return gcm_network_channel_.get();
122 TestGCMNetworkChannelDelegate* delegate() {
126 int url_fetchers_created_count() {
127 return url_fetchers_created_count_;
130 net::FakeURLFetcherFactory* url_fetcher_factory() {
131 return url_fetcher_factory_.get();
134 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
136 net::URLFetcherDelegate* delegate,
137 const std::string& response_data,
138 net::HttpStatusCode response_code,
139 net::URLRequestStatus::Status status) {
140 ++url_fetchers_created_count_;
141 return scoped_ptr<net::FakeURLFetcher>(new net::FakeURLFetcher(
142 url, delegate, response_data, response_code, status));
145 void RunLoopUntilIdle() {
146 base::RunLoop run_loop;
147 run_loop.RunUntilIdle();
151 base::MessageLoop message_loop_;
152 TestGCMNetworkChannelDelegate* delegate_;
153 scoped_ptr<GCMNetworkChannel> gcm_network_channel_;
154 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
155 scoped_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_;
156 int url_fetchers_created_count_;
159 TEST_F(GCMNetworkChannelTest, HappyCase) {
160 GURL url("http://invalid.url.com");
161 url_fetcher_factory()->SetFakeResponse(url, std::string(), net::HTTP_OK,
162 net::URLRequestStatus::SUCCESS);
164 // After construction GCMNetworkChannel should have called Register.
165 EXPECT_FALSE(delegate()->register_callback.is_null());
166 // Return valid registration id.
167 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
169 network_channel()->SendMessage("abra.cadabra");
170 // SendMessage should have triggered RequestToken. No HTTP request should be
172 EXPECT_FALSE(delegate()->request_token_callback.is_null());
173 EXPECT_EQ(url_fetchers_created_count(), 0);
174 // Return valid access token. This should trigger HTTP request.
175 delegate()->request_token_callback.Run(
176 GoogleServiceAuthError::AuthErrorNone(), "access.token");
178 EXPECT_EQ(url_fetchers_created_count(), 1);
180 // Return another access token. Message should be cleared by now and shouldn't
182 delegate()->request_token_callback.Run(
183 GoogleServiceAuthError::AuthErrorNone(), "access.token2");
185 EXPECT_EQ(url_fetchers_created_count(), 1);
188 TEST_F(GCMNetworkChannelTest, FailedRegister) {
189 // After construction GCMNetworkChannel should have called Register.
190 EXPECT_FALSE(delegate()->register_callback.is_null());
191 EXPECT_EQ(1, delegate()->register_call_count_);
192 // Return transient error from Register call.
193 delegate()->register_callback.Run("", gcm::GCMClient::NETWORK_ERROR);
195 // GcmNetworkChannel should have scheduled Register retry.
196 EXPECT_EQ(2, delegate()->register_call_count_);
197 // Return persistent error from Register call.
198 delegate()->register_callback.Run("", gcm::GCMClient::NOT_SIGNED_IN);
200 // GcmNetworkChannel should give up trying.
201 EXPECT_EQ(2, delegate()->register_call_count_);
203 network_channel()->SendMessage("abra.cadabra");
204 // SendMessage shouldn't trigger RequestToken.
205 EXPECT_TRUE(delegate()->request_token_callback.is_null());
206 EXPECT_EQ(0, url_fetchers_created_count());
209 TEST_F(GCMNetworkChannelTest, RegisterFinishesAfterSendMessage) {
210 GURL url("http://invalid.url.com");
211 url_fetcher_factory()->SetFakeResponse(url, "", net::HTTP_OK,
212 net::URLRequestStatus::SUCCESS);
214 // After construction GCMNetworkChannel should have called Register.
215 EXPECT_FALSE(delegate()->register_callback.is_null());
217 network_channel()->SendMessage("abra.cadabra");
218 // SendMessage shouldn't trigger RequestToken.
219 EXPECT_TRUE(delegate()->request_token_callback.is_null());
220 EXPECT_EQ(url_fetchers_created_count(), 0);
222 // Return valid registration id.
223 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
225 EXPECT_FALSE(delegate()->request_token_callback.is_null());
226 EXPECT_EQ(url_fetchers_created_count(), 0);
227 // Return valid access token. This should trigger HTTP request.
228 delegate()->request_token_callback.Run(
229 GoogleServiceAuthError::AuthErrorNone(), "access.token");
231 EXPECT_EQ(url_fetchers_created_count(), 1);
234 TEST_F(GCMNetworkChannelTest, RequestTokenFailure) {
235 // After construction GCMNetworkChannel should have called Register.
236 EXPECT_FALSE(delegate()->register_callback.is_null());
237 // Return valid registration id.
238 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
240 network_channel()->SendMessage("abra.cadabra");
241 // SendMessage should have triggered RequestToken. No HTTP request should be
243 EXPECT_FALSE(delegate()->request_token_callback.is_null());
244 EXPECT_EQ(url_fetchers_created_count(), 0);
245 // RequestToken returns failure.
246 delegate()->request_token_callback.Run(
247 GoogleServiceAuthError::FromConnectionError(1), "");
249 // Should be no HTTP requests.
250 EXPECT_EQ(url_fetchers_created_count(), 0);
253 TEST_F(GCMNetworkChannelTest, AuthErrorFromServer) {
254 // Setup fake response to return AUTH_ERROR.
255 GURL url("http://invalid.url.com");
256 url_fetcher_factory()->SetFakeResponse(url, "", net::HTTP_UNAUTHORIZED,
257 net::URLRequestStatus::SUCCESS);
259 // After construction GCMNetworkChannel should have called Register.
260 EXPECT_FALSE(delegate()->register_callback.is_null());
261 // Return valid registration id.
262 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
264 network_channel()->SendMessage("abra.cadabra");
265 // SendMessage should have triggered RequestToken. No HTTP request should be
267 EXPECT_FALSE(delegate()->request_token_callback.is_null());
268 EXPECT_EQ(url_fetchers_created_count(), 0);
269 // Return valid access token. This should trigger HTTP request.
270 delegate()->request_token_callback.Run(
271 GoogleServiceAuthError::AuthErrorNone(), "access.token");
273 EXPECT_EQ(url_fetchers_created_count(), 1);
274 EXPECT_EQ(delegate()->invalidated_token, "access.token");
277 // Following two tests are to check for memory leaks/crashes when Register and
278 // RequestToken don't complete by the teardown.
279 TEST_F(GCMNetworkChannelTest, RegisterNeverCompletes) {
280 network_channel()->SendMessage("abra.cadabra");
281 // Register should be called by now. Let's not complete and see what happens.
282 EXPECT_FALSE(delegate()->register_callback.is_null());
285 TEST_F(GCMNetworkChannelTest, RequestTokenNeverCompletes) {
286 network_channel()->SendMessage("abra.cadabra");
287 // Return valid registration id.
288 delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
289 // RequestToken should be called by now. Let's not complete and see what
291 EXPECT_FALSE(delegate()->request_token_callback.is_null());
295 } // namespace syncer