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 "google_apis/gcm/gcm_client_impl.h"
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"
11 #include "components/encryptor/os_crypt.h"
12 #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"
31 REGISTRATION_COMPLETED
,
32 UNREGISTRATION_COMPLETED
,
38 const uint64 kDeviceAndroidId
= 54321;
39 const uint64 kDeviceSecurityToken
= 12345;
40 const char kRegistrationResponsePrefix
[] = "token=";
41 const char kUnregistrationResponsePrefix
[] = "deleted=";
43 // Helper for building arbitrary data messages.
44 MCSMessage
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
;
49 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();
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
);
58 return MCSMessage(kDataMessageStanzaTag
, data_message
);
61 class FakeMCSClient
: public MCSClient
{
63 FakeMCSClient(base::Clock
* clock
,
64 ConnectionFactory
* connection_factory
);
65 virtual ~FakeMCSClient();
66 virtual void Login(uint64 android_id
, uint64 security_token
) OVERRIDE
;
67 virtual void SendMessage(const MCSMessage
& message
) OVERRIDE
;
68 void set_gcm_store(GCMStore
* gcm_store
);
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_
;
78 uint64 last_android_id_
;
79 uint64 last_security_token_
;
80 uint8 last_message_tag_
;
81 mcs_proto::DataMessageStanza last_data_message_stanza_
;
84 FakeMCSClient::FakeMCSClient(base::Clock
* clock
,
85 ConnectionFactory
* connection_factory
)
86 : MCSClient("", clock
, connection_factory
, NULL
),
88 last_security_token_(0u),
89 last_message_tag_(kNumProtoTypes
) {
92 FakeMCSClient::~FakeMCSClient() {
95 void FakeMCSClient::set_gcm_store(GCMStore
* gcm_store
) {
96 SetGCMStoreForTesting(gcm_store
);
99 void FakeMCSClient::Login(uint64 android_id
, uint64 security_token
) {
100 last_android_id_
= android_id
;
101 last_security_token_
= security_token
;
104 void 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()));
115 class GCMClientImplTest
: public testing::Test
,
116 public GCMClient::Delegate
{
119 virtual ~GCMClientImplTest();
121 virtual void SetUp() OVERRIDE
;
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
);
128 void CompleteUnregistration(const std::string
& app_id
);
130 // GCMClient::Delegate overrides (for verification).
131 virtual void OnRegisterFinished(const std::string
& app_id
,
132 const std::string
& registration_id
,
133 GCMClient::Result result
) OVERRIDE
;
134 virtual void OnUnregisterFinished(const std::string
& app_id
,
135 bool success
) OVERRIDE
;
136 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
)
142 virtual void OnMessagesDeleted(const std::string
& app_id
) OVERRIDE
;
143 virtual void OnMessageSendError(const std::string
& app_id
,
144 const std::string
& message_id
,
145 GCMClient::Result result
) OVERRIDE
;
146 virtual void OnGCMReady() OVERRIDE
;
148 GCMClientImpl
* gcm_client() const { return gcm_client_
.get(); }
149 FakeMCSClient
* mcs_client() const {
150 return reinterpret_cast<FakeMCSClient
*>(gcm_client_
->mcs_client_
.get());
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_
;
158 const std::string
& last_message_id() const { return last_message_id_
; }
159 GCMClient::Result
last_result() const { return last_result_
; }
160 const GCMClient::IncomingMessage
& last_message() const {
161 return last_message_
;
169 void PumpLoopUntilIdle();
172 base::SimpleTestClock
* clock() const {
173 return reinterpret_cast<base::SimpleTestClock
*>(gcm_client_
->clock_
.get());
176 // Variables used for verification.
177 LastEvent last_event_
;
178 std::string last_app_id_
;
179 std::string last_registration_id_
;
180 std::string last_message_id_
;
181 GCMClient::Result last_result_
;
182 GCMClient::IncomingMessage last_message_
;
184 scoped_ptr
<GCMClientImpl
> gcm_client_
;
185 scoped_ptr
<FakeConnectionFactory
> connection_factory_
;
187 base::MessageLoop message_loop_
;
188 scoped_ptr
<base::RunLoop
> run_loop_
;
189 net::TestURLFetcherFactory url_fetcher_factory_
;
191 // Injected to GCM client:
192 base::ScopedTempDir temp_directory_
;
193 scoped_refptr
<net::TestURLRequestContextGetter
> url_request_context_getter_
;
196 GCMClientImplTest::GCMClientImplTest()
198 last_result_(GCMClient::UNKNOWN_ERROR
),
199 url_request_context_getter_(new net::TestURLRequestContextGetter(
200 message_loop_
.message_loop_proxy())) {
203 GCMClientImplTest::~GCMClientImplTest() {}
205 void GCMClientImplTest::SetUp() {
206 ASSERT_TRUE(temp_directory_
.CreateUniqueTempDir());
207 run_loop_
.reset(new base::RunLoop
);
209 InitializeGCMClient();
212 void GCMClientImplTest::PumpLoop() {
214 run_loop_
.reset(new base::RunLoop());
217 void GCMClientImplTest::PumpLoopUntilIdle() {
218 run_loop_
->RunUntilIdle();
219 run_loop_
.reset(new base::RunLoop());
222 void GCMClientImplTest::QuitLoop() {
223 if (run_loop_
&& run_loop_
->running())
227 void GCMClientImplTest::BuildGCMClient() {
228 gcm_client_
.reset(new GCMClientImpl());
231 void GCMClientImplTest::CompleteCheckin(uint64 android_id
,
232 uint64 security_token
) {
233 checkin_proto::AndroidCheckinResponse response
;
234 response
.set_stats_ok(true);
235 response
.set_android_id(android_id
);
236 response
.set_security_token(security_token
);
238 std::string response_string
;
239 response
.SerializeToString(&response_string
);
241 net::TestURLFetcher
* fetcher
= url_fetcher_factory_
.GetFetcherByID(0);
242 ASSERT_TRUE(fetcher
);
243 fetcher
->set_response_code(net::HTTP_OK
);
244 fetcher
->SetResponseString(response_string
);
245 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
246 url_fetcher_factory_
.RemoveFetcherFromMap(0);
249 void GCMClientImplTest::CompleteRegistration(
250 const std::string
& registration_id
) {
251 std::string
response(kRegistrationResponsePrefix
);
252 response
.append(registration_id
);
253 net::TestURLFetcher
* fetcher
= url_fetcher_factory_
.GetFetcherByID(0);
254 ASSERT_TRUE(fetcher
);
255 fetcher
->set_response_code(net::HTTP_OK
);
256 fetcher
->SetResponseString(response
);
257 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
260 void GCMClientImplTest::CompleteUnregistration(
261 const std::string
& app_id
) {
262 std::string
response(kUnregistrationResponsePrefix
);
263 response
.append(app_id
);
264 net::TestURLFetcher
* fetcher
= url_fetcher_factory_
.GetFetcherByID(0);
265 ASSERT_TRUE(fetcher
);
266 fetcher
->set_response_code(net::HTTP_OK
);
267 fetcher
->SetResponseString(response
);
268 fetcher
->delegate()->OnURLFetchComplete(fetcher
);
271 void GCMClientImplTest::InitializeGCMClient() {
272 // Creating and advancing the clock.
273 gcm_client_
->clock_
.reset(new base::SimpleTestClock
);
274 clock()->Advance(base::TimeDelta::FromMilliseconds(1));
275 // Creating and injecting the mcs_client.
276 connection_factory_
.reset(new FakeConnectionFactory());
277 gcm_client_
->SetMCSClientForTesting(scoped_ptr
<MCSClient
>(
278 new FakeMCSClient(clock(), connection_factory_
.get())).Pass());
279 // Actual initialization.
280 checkin_proto::ChromeBuildProto chrome_build_proto
;
281 gcm_client_
->Initialize(chrome_build_proto
,
282 temp_directory_
.path(),
283 std::vector
<std::string
>(),
284 message_loop_
.message_loop_proxy(),
285 url_request_context_getter_
,
288 #if defined(OS_MACOSX)
289 // On OSX, prevent the Keychain permissions popup during unit tests.
290 OSCrypt::UseMockKeychain(true); // Must be after Initialize.
293 // Starting loading and check-in.
296 // Ensuring that mcs_client is using the same gcm_store as gcm_client.
297 mcs_client()->set_gcm_store(gcm_client_
->gcm_store_
.get());
299 CompleteCheckin(kDeviceAndroidId
, kDeviceSecurityToken
);
302 void GCMClientImplTest::ReceiveMessageFromMCS(const MCSMessage
& message
) {
303 gcm_client_
->OnMessageReceivedFromMCS(message
);
306 void GCMClientImplTest::OnGCMReady() {
307 last_event_
= LOADING_COMPLETED
;
311 void GCMClientImplTest::OnMessageReceived(
312 const std::string
& registration_id
,
313 const GCMClient::IncomingMessage
& message
) {
314 last_event_
= MESSAGE_RECEIVED
;
315 last_app_id_
= registration_id
;
316 last_message_
= message
;
320 void GCMClientImplTest::OnRegisterFinished(const std::string
& app_id
,
321 const std::string
& registration_id
,
322 GCMClient::Result result
) {
323 last_event_
= REGISTRATION_COMPLETED
;
324 last_app_id_
= app_id
;
325 last_registration_id_
= registration_id
;
326 last_result_
= result
;
329 void GCMClientImplTest::OnUnregisterFinished(const std::string
& app_id
,
331 last_event_
= UNREGISTRATION_COMPLETED
;
332 last_app_id_
= app_id
;
333 last_result_
= success
? GCMClient::SUCCESS
: GCMClient::UNKNOWN_ERROR
;
336 void GCMClientImplTest::OnMessagesDeleted(const std::string
& app_id
) {
337 last_event_
= MESSAGES_DELETED
;
338 last_app_id_
= app_id
;
341 void GCMClientImplTest::OnMessageSendError(const std::string
& app_id
,
342 const std::string
& message_id
,
343 GCMClient::Result result
) {
344 last_event_
= MESSAGE_SEND_ERROR
;
345 last_app_id_
= app_id
;
346 last_message_id_
= message_id
;
347 last_result_
= result
;
350 int64
GCMClientImplTest::CurrentTime() {
351 return clock()->Now().ToInternalValue() / base::Time::kMicrosecondsPerSecond
;
354 TEST_F(GCMClientImplTest
, LoadingCompleted
) {
355 EXPECT_EQ(LOADING_COMPLETED
, last_event());
356 EXPECT_EQ(kDeviceAndroidId
, mcs_client()->last_android_id());
357 EXPECT_EQ(kDeviceSecurityToken
, mcs_client()->last_security_token());
360 TEST_F(GCMClientImplTest
, CheckOut
) {
361 EXPECT_TRUE(mcs_client());
362 gcm_client()->CheckOut();
363 EXPECT_FALSE(mcs_client());
366 TEST_F(GCMClientImplTest
, RegisterApp
) {
367 std::vector
<std::string
> senders
;
368 senders
.push_back("sender");
369 gcm_client()->Register("app_id", "cert", senders
);
370 CompleteRegistration("reg_id");
372 EXPECT_EQ(REGISTRATION_COMPLETED
, last_event());
373 EXPECT_EQ("app_id", last_app_id());
374 EXPECT_EQ("reg_id", last_registration_id());
375 EXPECT_EQ(GCMClient::SUCCESS
, last_result());
378 TEST_F(GCMClientImplTest
, UnregisterApp
) {
379 gcm_client()->Unregister("app_id");
380 CompleteUnregistration("app_id");
382 EXPECT_EQ(UNREGISTRATION_COMPLETED
, last_event());
383 EXPECT_EQ("app_id", last_app_id());
384 EXPECT_EQ(GCMClient::SUCCESS
, last_result());
387 TEST_F(GCMClientImplTest
, DispatchDownstreamMessage
) {
388 std::map
<std::string
, std::string
> expected_data
;
389 expected_data
["message_type"] = "gcm";
390 expected_data
["key"] = "value";
391 expected_data
["key2"] = "value2";
392 MCSMessage
message(BuildDownstreamMessage(
393 "project_id", "app_id", expected_data
));
394 EXPECT_TRUE(message
.IsValid());
395 ReceiveMessageFromMCS(message
);
397 expected_data
.erase(expected_data
.find("message_type"));
398 EXPECT_EQ(MESSAGE_RECEIVED
, last_event());
399 EXPECT_EQ("app_id", last_app_id());
400 EXPECT_EQ(expected_data
.size(), last_message().data
.size());
401 EXPECT_EQ(expected_data
, last_message().data
);
404 TEST_F(GCMClientImplTest
, DispatchDownstreamMessageSendError
) {
405 std::map
<std::string
, std::string
> expected_data
;
406 expected_data
["message_type"] = "send_error";
407 expected_data
["google.message_id"] = "007";
408 MCSMessage
message(BuildDownstreamMessage(
409 "project_id", "app_id", expected_data
));
410 EXPECT_TRUE(message
.IsValid());
411 ReceiveMessageFromMCS(message
);
413 EXPECT_EQ(MESSAGE_SEND_ERROR
, last_event());
414 EXPECT_EQ("app_id", last_app_id());
415 EXPECT_EQ("007", last_message_id());
418 TEST_F(GCMClientImplTest
, DispatchDownstreamMessgaesDeleted
) {
419 std::map
<std::string
, std::string
> expected_data
;
420 expected_data
["message_type"] = "deleted_messages";
421 MCSMessage
message(BuildDownstreamMessage(
422 "project_id", "app_id", expected_data
));
423 EXPECT_TRUE(message
.IsValid());
424 ReceiveMessageFromMCS(message
);
426 EXPECT_EQ(MESSAGES_DELETED
, last_event());
427 EXPECT_EQ("app_id", last_app_id());
430 TEST_F(GCMClientImplTest
, SendMessage
) {
431 mcs_proto::DataMessageStanza stanza
;
434 GCMClient::OutgoingMessage message
;
436 message
.time_to_live
= 500;
437 message
.data
["key"] = "value";
438 gcm_client()->Send("app_id", "project_id", message
);
440 EXPECT_EQ(kDataMessageStanzaTag
, mcs_client()->last_message_tag());
441 EXPECT_EQ("app_id", mcs_client()->last_data_message_stanza().category());
442 EXPECT_EQ("project_id", mcs_client()->last_data_message_stanza().to());
443 EXPECT_EQ(500, mcs_client()->last_data_message_stanza().ttl());
444 EXPECT_EQ(CurrentTime(), mcs_client()->last_data_message_stanza().sent());
445 EXPECT_EQ("007", mcs_client()->last_data_message_stanza().id());
446 EXPECT_EQ("gcm@chrome.com", mcs_client()->last_data_message_stanza().from());
447 EXPECT_EQ("project_id", mcs_client()->last_data_message_stanza().to());
448 EXPECT_EQ("key", mcs_client()->last_data_message_stanza().app_data(0).key());
450 mcs_client()->last_data_message_stanza().app_data(0).value());