blob: f8129b4de39618da128536644edd4bc8b6bb8e60 [file] [log] [blame]
[email protected]848b1b62014-01-30 23:51:041// 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.
4
5#include "google_apis/gcm/gcm_client_impl.h"
6
7#include "base/files/scoped_temp_dir.h"
8#include "base/message_loop/message_loop.h"
9#include "base/run_loop.h"
10#include "base/test/simple_test_clock.h"
[email protected]c523d202014-03-18 01:34:5411#include "components/os_crypt/os_crypt.h"
[email protected]848b1b62014-01-30 23:51:0412#include "google_apis/gcm/base/mcs_message.h"
13#include "google_apis/gcm/base/mcs_util.h"
14#include "google_apis/gcm/engine/fake_connection_factory.h"
15#include "google_apis/gcm/engine/fake_connection_handler.h"
16#include "google_apis/gcm/protocol/android_checkin.pb.h"
17#include "google_apis/gcm/protocol/checkin.pb.h"
18#include "google_apis/gcm/protocol/mcs.pb.h"
19#include "net/url_request/test_url_fetcher_factory.h"
20#include "net/url_request/url_fetcher_delegate.h"
21#include "net/url_request/url_request_test_util.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24namespace gcm {
25
26namespace {
27
28enum LastEvent {
29 NONE,
30 LOADING_COMPLETED,
[email protected]848b1b62014-01-30 23:51:0431 REGISTRATION_COMPLETED,
[email protected]e4007042014-02-15 20:34:2832 UNREGISTRATION_COMPLETED,
[email protected]848b1b62014-01-30 23:51:0433 MESSAGE_SEND_ERROR,
34 MESSAGE_RECEIVED,
35 MESSAGES_DELETED,
36};
37
38const uint64 kDeviceAndroidId = 54321;
39const uint64 kDeviceSecurityToken = 12345;
40const char kRegistrationResponsePrefix[] = "token=";
[email protected]e4007042014-02-15 20:34:2841const char kUnregistrationResponsePrefix[] = "deleted=";
[email protected]848b1b62014-01-30 23:51:0442
43// Helper for building arbitrary data messages.
44MCSMessage BuildDownstreamMessage(
45 const std::string& project_id,
46 const std::string& app_id,
47 const std::map<std::string, std::string>& data) {
48 mcs_proto::DataMessageStanza data_message;
[email protected]848b1b62014-01-30 23:51:0449 data_message.set_from(project_id);
50 data_message.set_category(app_id);
51 for (std::map<std::string, std::string>::const_iterator iter = data.begin();
52 iter != data.end();
53 ++iter) {
54 mcs_proto::AppData* app_data = data_message.add_app_data();
55 app_data->set_key(iter->first);
56 app_data->set_value(iter->second);
57 }
58 return MCSMessage(kDataMessageStanzaTag, data_message);
59}
60
61class FakeMCSClient : public MCSClient {
62 public:
63 FakeMCSClient(base::Clock* clock,
64 ConnectionFactory* connection_factory);
65 virtual ~FakeMCSClient();
[email protected]5799d052014-02-12 20:47:3966 virtual void Login(uint64 android_id, uint64 security_token) OVERRIDE;
[email protected]848b1b62014-01-30 23:51:0467 virtual void SendMessage(const MCSMessage& message) OVERRIDE;
68 void set_gcm_store(GCMStore* gcm_store);
69
70 uint64 last_android_id() const { return last_android_id_; }
71 uint64 last_security_token() const { return last_security_token_; }
72 uint8 last_message_tag() const { return last_message_tag_; }
73 const mcs_proto::DataMessageStanza& last_data_message_stanza() const {
74 return last_data_message_stanza_;
75 }
76
77 private:
78 uint64 last_android_id_;
79 uint64 last_security_token_;
80 uint8 last_message_tag_;
81 mcs_proto::DataMessageStanza last_data_message_stanza_;
82};
83
84FakeMCSClient::FakeMCSClient(base::Clock* clock,
85 ConnectionFactory* connection_factory)
[email protected]e262fd12014-02-20 16:04:4786 : MCSClient("", clock, connection_factory, NULL),
[email protected]848b1b62014-01-30 23:51:0487 last_android_id_(0u),
88 last_security_token_(0u),
89 last_message_tag_(kNumProtoTypes) {
90}
91
92FakeMCSClient::~FakeMCSClient() {
93}
94
95void FakeMCSClient::set_gcm_store(GCMStore* gcm_store) {
96 SetGCMStoreForTesting(gcm_store);
97}
98
[email protected]5799d052014-02-12 20:47:3999void FakeMCSClient::Login(uint64 android_id, uint64 security_token) {
[email protected]848b1b62014-01-30 23:51:04100 last_android_id_ = android_id;
101 last_security_token_ = security_token;
102}
103
104void FakeMCSClient::SendMessage(const MCSMessage& message) {
105 last_message_tag_ = message.tag();
106 if (last_message_tag_ == kDataMessageStanzaTag) {
107 last_data_message_stanza_.CopyFrom(
108 reinterpret_cast<const mcs_proto::DataMessageStanza&>(
109 message.GetProtobuf()));
110 }
111}
112
113} // namespace
114
115class GCMClientImplTest : public testing::Test,
116 public GCMClient::Delegate {
117 public:
118 GCMClientImplTest();
119 virtual ~GCMClientImplTest();
120
121 virtual void SetUp() OVERRIDE;
122
123 void BuildGCMClient();
124 void InitializeGCMClient();
125 void ReceiveMessageFromMCS(const MCSMessage& message);
126 void CompleteCheckin(uint64 android_id, uint64 security_token);
127 void CompleteRegistration(const std::string& registration_id);
[email protected]e4007042014-02-15 20:34:28128 void CompleteUnregistration(const std::string& app_id);
[email protected]848b1b62014-01-30 23:51:04129
130 // GCMClient::Delegate overrides (for verification).
[email protected]848b1b62014-01-30 23:51:04131 virtual void OnRegisterFinished(const std::string& app_id,
132 const std::string& registration_id,
133 GCMClient::Result result) OVERRIDE;
[email protected]e4007042014-02-15 20:34:28134 virtual void OnUnregisterFinished(const std::string& app_id,
[email protected]0e88e1d12014-03-19 06:53:08135 GCMClient::Result result) OVERRIDE;
[email protected]848b1b62014-01-30 23:51:04136 virtual void OnSendFinished(const std::string& app_id,
137 const std::string& message_id,
138 GCMClient::Result result) OVERRIDE {}
139 virtual void OnMessageReceived(const std::string& registration_id,
140 const GCMClient::IncomingMessage& message)
141 OVERRIDE;
142 virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE;
[email protected]c6fe36b2014-03-11 10:58:12143 virtual void OnMessageSendError(
144 const std::string& app_id,
145 const gcm::GCMClient::SendErrorDetails& send_error_details) OVERRIDE;
[email protected]86625df2014-01-31 03:47:58146 virtual void OnGCMReady() OVERRIDE;
[email protected]848b1b62014-01-30 23:51:04147
[email protected]848b1b62014-01-30 23:51:04148 GCMClientImpl* gcm_client() const { return gcm_client_.get(); }
149 FakeMCSClient* mcs_client() const {
150 return reinterpret_cast<FakeMCSClient*>(gcm_client_->mcs_client_.get());
151 }
152
153 LastEvent last_event() const { return last_event_; }
154 const std::string& last_app_id() const { return last_app_id_; }
155 const std::string& last_registration_id() const {
156 return last_registration_id_;
157 }
158 const std::string& last_message_id() const { return last_message_id_; }
159 GCMClient::Result last_result() const { return last_result_; }
[email protected]848b1b62014-01-30 23:51:04160 const GCMClient::IncomingMessage& last_message() const {
161 return last_message_;
162 }
[email protected]c6fe36b2014-03-11 10:58:12163 const GCMClient::SendErrorDetails& last_error_details() const {
164 return last_error_details_;
165 }
[email protected]848b1b62014-01-30 23:51:04166
167 int64 CurrentTime();
168
169 private:
170 // Tooling.
171 void PumpLoop();
172 void PumpLoopUntilIdle();
173 void QuitLoop();
174
175 base::SimpleTestClock* clock() const {
176 return reinterpret_cast<base::SimpleTestClock*>(gcm_client_->clock_.get());
177 }
178
179 // Variables used for verification.
180 LastEvent last_event_;
181 std::string last_app_id_;
182 std::string last_registration_id_;
183 std::string last_message_id_;
184 GCMClient::Result last_result_;
[email protected]848b1b62014-01-30 23:51:04185 GCMClient::IncomingMessage last_message_;
[email protected]c6fe36b2014-03-11 10:58:12186 GCMClient::SendErrorDetails last_error_details_;
[email protected]848b1b62014-01-30 23:51:04187
188 scoped_ptr<GCMClientImpl> gcm_client_;
[email protected]848b1b62014-01-30 23:51:04189 scoped_ptr<FakeConnectionFactory> connection_factory_;
190
191 base::MessageLoop message_loop_;
192 scoped_ptr<base::RunLoop> run_loop_;
193 net::TestURLFetcherFactory url_fetcher_factory_;
194
195 // Injected to GCM client:
196 base::ScopedTempDir temp_directory_;
197 scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_;
198};
199
200GCMClientImplTest::GCMClientImplTest()
201 : last_event_(NONE),
202 last_result_(GCMClient::UNKNOWN_ERROR),
203 url_request_context_getter_(new net::TestURLRequestContextGetter(
204 message_loop_.message_loop_proxy())) {
205}
206
207GCMClientImplTest::~GCMClientImplTest() {}
208
209void GCMClientImplTest::SetUp() {
210 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
211 run_loop_.reset(new base::RunLoop);
212 BuildGCMClient();
213 InitializeGCMClient();
[email protected]848b1b62014-01-30 23:51:04214}
215
216void GCMClientImplTest::PumpLoop() {
217 run_loop_->Run();
218 run_loop_.reset(new base::RunLoop());
219}
220
221void GCMClientImplTest::PumpLoopUntilIdle() {
222 run_loop_->RunUntilIdle();
223 run_loop_.reset(new base::RunLoop());
224}
225
226void GCMClientImplTest::QuitLoop() {
227 if (run_loop_ && run_loop_->running())
228 run_loop_->Quit();
229}
230
231void GCMClientImplTest::BuildGCMClient() {
232 gcm_client_.reset(new GCMClientImpl());
233}
234
235void GCMClientImplTest::CompleteCheckin(uint64 android_id,
236 uint64 security_token) {
237 checkin_proto::AndroidCheckinResponse response;
238 response.set_stats_ok(true);
239 response.set_android_id(android_id);
240 response.set_security_token(security_token);
241
242 std::string response_string;
243 response.SerializeToString(&response_string);
244
245 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
246 ASSERT_TRUE(fetcher);
247 fetcher->set_response_code(net::HTTP_OK);
248 fetcher->SetResponseString(response_string);
249 fetcher->delegate()->OnURLFetchComplete(fetcher);
250 url_fetcher_factory_.RemoveFetcherFromMap(0);
251}
252
253void GCMClientImplTest::CompleteRegistration(
254 const std::string& registration_id) {
255 std::string response(kRegistrationResponsePrefix);
256 response.append(registration_id);
257 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
258 ASSERT_TRUE(fetcher);
259 fetcher->set_response_code(net::HTTP_OK);
260 fetcher->SetResponseString(response);
261 fetcher->delegate()->OnURLFetchComplete(fetcher);
[email protected]e4007042014-02-15 20:34:28262}
263
264void GCMClientImplTest::CompleteUnregistration(
265 const std::string& app_id) {
266 std::string response(kUnregistrationResponsePrefix);
267 response.append(app_id);
268 net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
269 ASSERT_TRUE(fetcher);
270 fetcher->set_response_code(net::HTTP_OK);
271 fetcher->SetResponseString(response);
272 fetcher->delegate()->OnURLFetchComplete(fetcher);
[email protected]848b1b62014-01-30 23:51:04273}
274
275void GCMClientImplTest::InitializeGCMClient() {
276 // Creating and advancing the clock.
277 gcm_client_->clock_.reset(new base::SimpleTestClock);
278 clock()->Advance(base::TimeDelta::FromMilliseconds(1));
279 // Creating and injecting the mcs_client.
280 connection_factory_.reset(new FakeConnectionFactory());
281 gcm_client_->SetMCSClientForTesting(scoped_ptr<MCSClient>(
282 new FakeMCSClient(clock(), connection_factory_.get())).Pass());
283 // Actual initialization.
284 checkin_proto::ChromeBuildProto chrome_build_proto;
285 gcm_client_->Initialize(chrome_build_proto,
286 temp_directory_.path(),
[email protected]495a7db92014-02-22 07:49:59287 std::vector<std::string>(),
[email protected]848b1b62014-01-30 23:51:04288 message_loop_.message_loop_proxy(),
[email protected]5799d052014-02-12 20:47:39289 url_request_context_getter_,
290 this);
[email protected]d3a4b2e2014-02-27 13:46:54291
[email protected]0693d5162014-02-12 00:20:17292#if defined(OS_MACOSX)
293 // On OSX, prevent the Keychain permissions popup during unit tests.
[email protected]92cdb1ca2014-02-28 18:34:10294 OSCrypt::UseMockKeychain(true); // Must be after Initialize.
[email protected]0693d5162014-02-12 00:20:17295#endif
[email protected]d3a4b2e2014-02-27 13:46:54296
297 // Starting loading and check-in.
298 gcm_client_->Load();
299
[email protected]848b1b62014-01-30 23:51:04300 // Ensuring that mcs_client is using the same gcm_store as gcm_client.
301 mcs_client()->set_gcm_store(gcm_client_->gcm_store_.get());
302 PumpLoopUntilIdle();
303 CompleteCheckin(kDeviceAndroidId, kDeviceSecurityToken);
[email protected]848b1b62014-01-30 23:51:04304}
305
306void GCMClientImplTest::ReceiveMessageFromMCS(const MCSMessage& message) {
307 gcm_client_->OnMessageReceivedFromMCS(message);
308}
309
[email protected]86625df2014-01-31 03:47:58310void GCMClientImplTest::OnGCMReady() {
[email protected]848b1b62014-01-30 23:51:04311 last_event_ = LOADING_COMPLETED;
312 QuitLoop();
313}
314
[email protected]848b1b62014-01-30 23:51:04315void GCMClientImplTest::OnMessageReceived(
316 const std::string& registration_id,
317 const GCMClient::IncomingMessage& message) {
318 last_event_ = MESSAGE_RECEIVED;
319 last_app_id_ = registration_id;
320 last_message_ = message;
321 QuitLoop();
322}
323
324void GCMClientImplTest::OnRegisterFinished(const std::string& app_id,
325 const std::string& registration_id,
326 GCMClient::Result result) {
327 last_event_ = REGISTRATION_COMPLETED;
328 last_app_id_ = app_id;
329 last_registration_id_ = registration_id;
330 last_result_ = result;
331}
332
[email protected]e4007042014-02-15 20:34:28333void GCMClientImplTest::OnUnregisterFinished(const std::string& app_id,
[email protected]0e88e1d12014-03-19 06:53:08334 GCMClient::Result result) {
[email protected]e4007042014-02-15 20:34:28335 last_event_ = UNREGISTRATION_COMPLETED;
336 last_app_id_ = app_id;
[email protected]0e88e1d12014-03-19 06:53:08337 last_result_ = result;
[email protected]e4007042014-02-15 20:34:28338}
339
[email protected]848b1b62014-01-30 23:51:04340void GCMClientImplTest::OnMessagesDeleted(const std::string& app_id) {
341 last_event_ = MESSAGES_DELETED;
342 last_app_id_ = app_id;
343}
344
[email protected]c6fe36b2014-03-11 10:58:12345void GCMClientImplTest::OnMessageSendError(
346 const std::string& app_id,
347 const gcm::GCMClient::SendErrorDetails& send_error_details) {
[email protected]848b1b62014-01-30 23:51:04348 last_event_ = MESSAGE_SEND_ERROR;
349 last_app_id_ = app_id;
[email protected]c6fe36b2014-03-11 10:58:12350 last_error_details_ = send_error_details;
[email protected]848b1b62014-01-30 23:51:04351}
352
353int64 GCMClientImplTest::CurrentTime() {
354 return clock()->Now().ToInternalValue() / base::Time::kMicrosecondsPerSecond;
355}
356
[email protected]848b1b62014-01-30 23:51:04357TEST_F(GCMClientImplTest, LoadingCompleted) {
358 EXPECT_EQ(LOADING_COMPLETED, last_event());
359 EXPECT_EQ(kDeviceAndroidId, mcs_client()->last_android_id());
360 EXPECT_EQ(kDeviceSecurityToken, mcs_client()->last_security_token());
361}
362
[email protected]8e3ee1da2014-02-13 05:21:03363TEST_F(GCMClientImplTest, CheckOut) {
364 EXPECT_TRUE(mcs_client());
365 gcm_client()->CheckOut();
366 EXPECT_FALSE(mcs_client());
367}
368
[email protected]848b1b62014-01-30 23:51:04369TEST_F(GCMClientImplTest, RegisterApp) {
370 std::vector<std::string> senders;
371 senders.push_back("sender");
[email protected]864b73c2014-03-05 20:18:15372 gcm_client()->Register("app_id", senders);
[email protected]848b1b62014-01-30 23:51:04373 CompleteRegistration("reg_id");
374
375 EXPECT_EQ(REGISTRATION_COMPLETED, last_event());
376 EXPECT_EQ("app_id", last_app_id());
377 EXPECT_EQ("reg_id", last_registration_id());
378 EXPECT_EQ(GCMClient::SUCCESS, last_result());
379}
380
[email protected]e4007042014-02-15 20:34:28381TEST_F(GCMClientImplTest, UnregisterApp) {
382 gcm_client()->Unregister("app_id");
383 CompleteUnregistration("app_id");
384
385 EXPECT_EQ(UNREGISTRATION_COMPLETED, last_event());
386 EXPECT_EQ("app_id", last_app_id());
387 EXPECT_EQ(GCMClient::SUCCESS, last_result());
388}
389
[email protected]848b1b62014-01-30 23:51:04390TEST_F(GCMClientImplTest, DispatchDownstreamMessage) {
391 std::map<std::string, std::string> expected_data;
392 expected_data["message_type"] = "gcm";
393 expected_data["key"] = "value";
394 expected_data["key2"] = "value2";
395 MCSMessage message(BuildDownstreamMessage(
396 "project_id", "app_id", expected_data));
397 EXPECT_TRUE(message.IsValid());
398 ReceiveMessageFromMCS(message);
399
400 expected_data.erase(expected_data.find("message_type"));
401 EXPECT_EQ(MESSAGE_RECEIVED, last_event());
402 EXPECT_EQ("app_id", last_app_id());
403 EXPECT_EQ(expected_data.size(), last_message().data.size());
404 EXPECT_EQ(expected_data, last_message().data);
[email protected]8d3af382014-03-07 00:58:41405 EXPECT_EQ("project_id", last_message().sender_id);
[email protected]848b1b62014-01-30 23:51:04406}
407
408TEST_F(GCMClientImplTest, DispatchDownstreamMessageSendError) {
409 std::map<std::string, std::string> expected_data;
410 expected_data["message_type"] = "send_error";
411 expected_data["google.message_id"] = "007";
[email protected]c6fe36b2014-03-11 10:58:12412 expected_data["error_details"] = "some details";
[email protected]848b1b62014-01-30 23:51:04413 MCSMessage message(BuildDownstreamMessage(
414 "project_id", "app_id", expected_data));
415 EXPECT_TRUE(message.IsValid());
416 ReceiveMessageFromMCS(message);
417
418 EXPECT_EQ(MESSAGE_SEND_ERROR, last_event());
419 EXPECT_EQ("app_id", last_app_id());
[email protected]c6fe36b2014-03-11 10:58:12420 EXPECT_EQ("007", last_error_details().message_id);
421 EXPECT_EQ(1UL, last_error_details().additional_data.size());
422 GCMClient::MessageData::const_iterator iter =
423 last_error_details().additional_data.find("error_details");
424 EXPECT_TRUE(iter != last_error_details().additional_data.end());
425 EXPECT_EQ("some details", iter->second);
[email protected]848b1b62014-01-30 23:51:04426}
427
428TEST_F(GCMClientImplTest, DispatchDownstreamMessgaesDeleted) {
429 std::map<std::string, std::string> expected_data;
430 expected_data["message_type"] = "deleted_messages";
431 MCSMessage message(BuildDownstreamMessage(
432 "project_id", "app_id", expected_data));
433 EXPECT_TRUE(message.IsValid());
434 ReceiveMessageFromMCS(message);
435
436 EXPECT_EQ(MESSAGES_DELETED, last_event());
437 EXPECT_EQ("app_id", last_app_id());
438}
439
440TEST_F(GCMClientImplTest, SendMessage) {
441 mcs_proto::DataMessageStanza stanza;
442 stanza.set_ttl(500);
443
444 GCMClient::OutgoingMessage message;
445 message.id = "007";
446 message.time_to_live = 500;
447 message.data["key"] = "value";
[email protected]5799d052014-02-12 20:47:39448 gcm_client()->Send("app_id", "project_id", message);
[email protected]848b1b62014-01-30 23:51:04449
450 EXPECT_EQ(kDataMessageStanzaTag, mcs_client()->last_message_tag());
451 EXPECT_EQ("app_id", mcs_client()->last_data_message_stanza().category());
452 EXPECT_EQ("project_id", mcs_client()->last_data_message_stanza().to());
453 EXPECT_EQ(500, mcs_client()->last_data_message_stanza().ttl());
454 EXPECT_EQ(CurrentTime(), mcs_client()->last_data_message_stanza().sent());
455 EXPECT_EQ("007", mcs_client()->last_data_message_stanza().id());
[email protected]848b1b62014-01-30 23:51:04456 EXPECT_EQ("[email protected]", mcs_client()->last_data_message_stanza().from());
457 EXPECT_EQ("project_id", mcs_client()->last_data_message_stanza().to());
458 EXPECT_EQ("key", mcs_client()->last_data_message_stanza().app_data(0).key());
459 EXPECT_EQ("value",
460 mcs_client()->last_data_message_stanza().app_data(0).value());
461}
462
463} // namespace gcm