[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / google_apis / gcm / engine / gcm_store_impl_unittest.cc
blob7b9c89365291e1b8275a08953b35294ce59e093e
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/engine/gcm_store_impl.h"
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/run_loop.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "google_apis/gcm/base/fake_encryptor.h"
19 #include "google_apis/gcm/base/mcs_message.h"
20 #include "google_apis/gcm/base/mcs_util.h"
21 #include "google_apis/gcm/protocol/mcs.pb.h"
22 #include "testing/gtest/include/gtest/gtest.h"
24 namespace gcm {
26 namespace {
28 // Number of persistent ids to use in tests.
29 const int kNumPersistentIds = 10;
31 // Number of per-app messages in tests.
32 const int kNumMessagesPerApp = 20;
34 // App name for testing.
35 const char kAppName[] = "my_app";
37 // Category name for testing.
38 const char kCategoryName[] = "my_category";
40 const uint64 kDeviceId = 22;
41 const uint64 kDeviceToken = 55;
43 class GCMStoreImplTest : public testing::Test {
44 public:
45 GCMStoreImplTest();
46 virtual ~GCMStoreImplTest();
48 virtual void SetUp() OVERRIDE;
50 scoped_ptr<GCMStore> BuildGCMStore();
52 std::string GetNextPersistentId();
54 void PumpLoop();
56 void LoadCallback(scoped_ptr<GCMStore::LoadResult>* result_dst,
57 scoped_ptr<GCMStore::LoadResult> result);
58 void UpdateCallback(bool success);
60 protected:
61 base::MessageLoop message_loop_;
62 base::ScopedTempDir temp_directory_;
63 bool expected_success_;
64 uint64 next_persistent_id_;
65 scoped_ptr<base::RunLoop> run_loop_;
68 GCMStoreImplTest::GCMStoreImplTest()
69 : expected_success_(true),
70 next_persistent_id_(base::Time::Now().ToInternalValue()) {
71 EXPECT_TRUE(temp_directory_.CreateUniqueTempDir());
72 run_loop_.reset(new base::RunLoop());
75 GCMStoreImplTest::~GCMStoreImplTest() {}
77 void GCMStoreImplTest::SetUp() {
78 testing::Test::SetUp();
81 scoped_ptr<GCMStore> GCMStoreImplTest::BuildGCMStore() {
82 return scoped_ptr<GCMStore>(new GCMStoreImpl(
83 temp_directory_.path(),
84 message_loop_.message_loop_proxy(),
85 make_scoped_ptr<Encryptor>(new FakeEncryptor)));
88 std::string GCMStoreImplTest::GetNextPersistentId() {
89 return base::Uint64ToString(next_persistent_id_++);
92 void GCMStoreImplTest::PumpLoop() { message_loop_.RunUntilIdle(); }
94 void GCMStoreImplTest::LoadCallback(
95 scoped_ptr<GCMStore::LoadResult>* result_dst,
96 scoped_ptr<GCMStore::LoadResult> result) {
97 ASSERT_TRUE(result->success);
98 *result_dst = result.Pass();
99 run_loop_->Quit();
100 run_loop_.reset(new base::RunLoop());
103 void GCMStoreImplTest::UpdateCallback(bool success) {
104 ASSERT_EQ(expected_success_, success);
107 // Verify creating a new database and loading it.
108 TEST_F(GCMStoreImplTest, LoadNew) {
109 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
110 scoped_ptr<GCMStore::LoadResult> load_result;
111 gcm_store->Load(base::Bind(
112 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
113 PumpLoop();
115 EXPECT_EQ(0U, load_result->device_android_id);
116 EXPECT_EQ(0U, load_result->device_security_token);
117 EXPECT_TRUE(load_result->incoming_messages.empty());
118 EXPECT_TRUE(load_result->outgoing_messages.empty());
119 EXPECT_TRUE(load_result->gservices_settings.empty());
120 EXPECT_EQ(base::Time::FromInternalValue(0LL), load_result->last_checkin_time);
123 TEST_F(GCMStoreImplTest, DeviceCredentials) {
124 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
125 scoped_ptr<GCMStore::LoadResult> load_result;
126 gcm_store->Load(base::Bind(
127 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
128 PumpLoop();
130 gcm_store->SetDeviceCredentials(
131 kDeviceId,
132 kDeviceToken,
133 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
134 PumpLoop();
136 gcm_store = BuildGCMStore().Pass();
137 gcm_store->Load(base::Bind(
138 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
139 PumpLoop();
141 ASSERT_EQ(kDeviceId, load_result->device_android_id);
142 ASSERT_EQ(kDeviceToken, load_result->device_security_token);
145 TEST_F(GCMStoreImplTest, LastCheckinTime) {
146 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
147 scoped_ptr<GCMStore::LoadResult> load_result;
148 gcm_store->Load(base::Bind(
149 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
150 PumpLoop();
152 base::Time last_checkin_time = base::Time::Now();
154 gcm_store->SetLastCheckinTime(
155 last_checkin_time,
156 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
157 PumpLoop();
159 gcm_store = BuildGCMStore().Pass();
160 gcm_store->Load(base::Bind(
161 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
162 PumpLoop();
163 ASSERT_EQ(last_checkin_time, load_result->last_checkin_time);
166 TEST_F(GCMStoreImplTest, GServicesSettings_ProtocolV2) {
167 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
168 scoped_ptr<GCMStore::LoadResult> load_result;
169 gcm_store->Load(base::Bind(
170 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
171 PumpLoop();
173 std::map<std::string, std::string> settings;
174 settings["checkin_interval"] = "12345";
175 settings["mcs_port"] = "438";
176 settings["checkin_url"] = "http://checkin.google.com";
177 std::string digest = "digest1";
179 gcm_store->SetGServicesSettings(
180 settings,
181 digest,
182 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
183 PumpLoop();
185 gcm_store = BuildGCMStore().Pass();
186 gcm_store->Load(base::Bind(
187 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
188 PumpLoop();
190 ASSERT_EQ(settings, load_result->gservices_settings);
191 ASSERT_EQ(digest, load_result->gservices_digest);
193 // Remove some, and add some.
194 settings.clear();
195 settings["checkin_interval"] = "54321";
196 settings["registration_url"] = "http://registration.google.com";
197 digest = "digest2";
199 gcm_store->SetGServicesSettings(
200 settings,
201 digest,
202 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
203 PumpLoop();
205 gcm_store = BuildGCMStore().Pass();
206 gcm_store->Load(base::Bind(
207 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
208 PumpLoop();
210 ASSERT_EQ(settings, load_result->gservices_settings);
211 ASSERT_EQ(digest, load_result->gservices_digest);
214 TEST_F(GCMStoreImplTest, Registrations) {
215 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
216 scoped_ptr<GCMStore::LoadResult> load_result;
217 gcm_store->Load(base::Bind(
218 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
219 PumpLoop();
221 // Add one registration with one sender.
222 linked_ptr<RegistrationInfo> registration1(new RegistrationInfo);
223 registration1->sender_ids.push_back("sender1");
224 registration1->registration_id = "registration1";
225 gcm_store->AddRegistration(
226 "app1",
227 registration1,
228 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
229 PumpLoop();
231 // Add one registration with multiple senders.
232 linked_ptr<RegistrationInfo> registration2(new RegistrationInfo);
233 registration2->sender_ids.push_back("sender2_1");
234 registration2->sender_ids.push_back("sender2_2");
235 registration2->registration_id = "registration2";
236 gcm_store->AddRegistration(
237 "app2",
238 registration2,
239 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
240 PumpLoop();
242 gcm_store = BuildGCMStore().Pass();
243 gcm_store->Load(base::Bind(
244 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
245 PumpLoop();
247 ASSERT_EQ(2u, load_result->registrations.size());
248 ASSERT_TRUE(load_result->registrations.find("app1") !=
249 load_result->registrations.end());
250 EXPECT_EQ(registration1->registration_id,
251 load_result->registrations["app1"]->registration_id);
252 ASSERT_EQ(1u, load_result->registrations["app1"]->sender_ids.size());
253 EXPECT_EQ(registration1->sender_ids[0],
254 load_result->registrations["app1"]->sender_ids[0]);
255 ASSERT_TRUE(load_result->registrations.find("app2") !=
256 load_result->registrations.end());
257 EXPECT_EQ(registration2->registration_id,
258 load_result->registrations["app2"]->registration_id);
259 ASSERT_EQ(2u, load_result->registrations["app2"]->sender_ids.size());
260 EXPECT_EQ(registration2->sender_ids[0],
261 load_result->registrations["app2"]->sender_ids[0]);
262 EXPECT_EQ(registration2->sender_ids[1],
263 load_result->registrations["app2"]->sender_ids[1]);
266 // Verify saving some incoming messages, reopening the directory, and then
267 // removing those incoming messages.
268 TEST_F(GCMStoreImplTest, IncomingMessages) {
269 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
270 scoped_ptr<GCMStore::LoadResult> load_result;
271 gcm_store->Load(base::Bind(
272 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
273 PumpLoop();
275 std::vector<std::string> persistent_ids;
276 for (int i = 0; i < kNumPersistentIds; ++i) {
277 persistent_ids.push_back(GetNextPersistentId());
278 gcm_store->AddIncomingMessage(
279 persistent_ids.back(),
280 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
281 PumpLoop();
284 gcm_store = BuildGCMStore().Pass();
285 gcm_store->Load(base::Bind(
286 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
287 PumpLoop();
289 ASSERT_EQ(persistent_ids, load_result->incoming_messages);
290 ASSERT_TRUE(load_result->outgoing_messages.empty());
292 gcm_store->RemoveIncomingMessages(
293 persistent_ids,
294 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
295 PumpLoop();
297 gcm_store = BuildGCMStore().Pass();
298 load_result->incoming_messages.clear();
299 gcm_store->Load(base::Bind(
300 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
301 PumpLoop();
303 ASSERT_TRUE(load_result->incoming_messages.empty());
304 ASSERT_TRUE(load_result->outgoing_messages.empty());
307 // Verify saving some outgoing messages, reopening the directory, and then
308 // removing those outgoing messages.
309 TEST_F(GCMStoreImplTest, OutgoingMessages) {
310 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
311 scoped_ptr<GCMStore::LoadResult> load_result;
312 gcm_store->Load(base::Bind(
313 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
314 PumpLoop();
316 std::vector<std::string> persistent_ids;
317 const int kNumPersistentIds = 10;
318 for (int i = 0; i < kNumPersistentIds; ++i) {
319 persistent_ids.push_back(GetNextPersistentId());
320 mcs_proto::DataMessageStanza message;
321 message.set_from(kAppName + persistent_ids.back());
322 message.set_category(kCategoryName + persistent_ids.back());
323 gcm_store->AddOutgoingMessage(
324 persistent_ids.back(),
325 MCSMessage(message),
326 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
327 PumpLoop();
330 gcm_store = BuildGCMStore().Pass();
331 gcm_store->Load(base::Bind(
332 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
333 PumpLoop();
335 ASSERT_TRUE(load_result->incoming_messages.empty());
336 ASSERT_EQ(load_result->outgoing_messages.size(), persistent_ids.size());
337 for (int i = 0; i < kNumPersistentIds; ++i) {
338 std::string id = persistent_ids[i];
339 ASSERT_TRUE(load_result->outgoing_messages[id].get());
340 const mcs_proto::DataMessageStanza* message =
341 reinterpret_cast<mcs_proto::DataMessageStanza*>(
342 load_result->outgoing_messages[id].get());
343 ASSERT_EQ(message->from(), kAppName + id);
344 ASSERT_EQ(message->category(), kCategoryName + id);
347 gcm_store->RemoveOutgoingMessages(
348 persistent_ids,
349 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
350 PumpLoop();
352 gcm_store = BuildGCMStore().Pass();
353 load_result->outgoing_messages.clear();
354 gcm_store->Load(base::Bind(
355 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
356 PumpLoop();
358 ASSERT_TRUE(load_result->incoming_messages.empty());
359 ASSERT_TRUE(load_result->outgoing_messages.empty());
362 // Verify incoming and outgoing messages don't conflict.
363 TEST_F(GCMStoreImplTest, IncomingAndOutgoingMessages) {
364 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
365 scoped_ptr<GCMStore::LoadResult> load_result;
366 gcm_store->Load(base::Bind(
367 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
368 PumpLoop();
370 std::vector<std::string> persistent_ids;
371 const int kNumPersistentIds = 10;
372 for (int i = 0; i < kNumPersistentIds; ++i) {
373 persistent_ids.push_back(GetNextPersistentId());
374 gcm_store->AddIncomingMessage(
375 persistent_ids.back(),
376 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
377 PumpLoop();
379 mcs_proto::DataMessageStanza message;
380 message.set_from(kAppName + persistent_ids.back());
381 message.set_category(kCategoryName + persistent_ids.back());
382 gcm_store->AddOutgoingMessage(
383 persistent_ids.back(),
384 MCSMessage(message),
385 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
386 PumpLoop();
389 gcm_store = BuildGCMStore().Pass();
390 gcm_store->Load(base::Bind(
391 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
392 PumpLoop();
394 ASSERT_EQ(persistent_ids, load_result->incoming_messages);
395 ASSERT_EQ(load_result->outgoing_messages.size(), persistent_ids.size());
396 for (int i = 0; i < kNumPersistentIds; ++i) {
397 std::string id = persistent_ids[i];
398 ASSERT_TRUE(load_result->outgoing_messages[id].get());
399 const mcs_proto::DataMessageStanza* message =
400 reinterpret_cast<mcs_proto::DataMessageStanza*>(
401 load_result->outgoing_messages[id].get());
402 ASSERT_EQ(message->from(), kAppName + id);
403 ASSERT_EQ(message->category(), kCategoryName + id);
406 gcm_store->RemoveIncomingMessages(
407 persistent_ids,
408 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
409 PumpLoop();
410 gcm_store->RemoveOutgoingMessages(
411 persistent_ids,
412 base::Bind(&GCMStoreImplTest::UpdateCallback, base::Unretained(this)));
413 PumpLoop();
415 gcm_store = BuildGCMStore().Pass();
416 load_result->incoming_messages.clear();
417 load_result->outgoing_messages.clear();
418 gcm_store->Load(base::Bind(
419 &GCMStoreImplTest::LoadCallback, base::Unretained(this), &load_result));
420 PumpLoop();
422 ASSERT_TRUE(load_result->incoming_messages.empty());
423 ASSERT_TRUE(load_result->outgoing_messages.empty());
426 // Test that per-app message limits are enforced, persisted across restarts,
427 // and updated as messages are removed.
428 TEST_F(GCMStoreImplTest, PerAppMessageLimits) {
429 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
430 scoped_ptr<GCMStore::LoadResult> load_result;
431 gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
432 base::Unretained(this),
433 &load_result));
435 // Add the initial (below app limit) messages.
436 for (int i = 0; i < kNumMessagesPerApp; ++i) {
437 mcs_proto::DataMessageStanza message;
438 message.set_from(kAppName);
439 message.set_category(kCategoryName);
440 EXPECT_TRUE(gcm_store->AddOutgoingMessage(
441 base::IntToString(i),
442 MCSMessage(message),
443 base::Bind(&GCMStoreImplTest::UpdateCallback,
444 base::Unretained(this))));
445 PumpLoop();
448 // Attempting to add some more should fail.
449 for (int i = 0; i < kNumMessagesPerApp; ++i) {
450 mcs_proto::DataMessageStanza message;
451 message.set_from(kAppName);
452 message.set_category(kCategoryName);
453 EXPECT_FALSE(gcm_store->AddOutgoingMessage(
454 base::IntToString(i + kNumMessagesPerApp),
455 MCSMessage(message),
456 base::Bind(&GCMStoreImplTest::UpdateCallback,
457 base::Unretained(this))));
458 PumpLoop();
461 // Tear down and restore the database.
462 gcm_store = BuildGCMStore().Pass();
463 gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
464 base::Unretained(this),
465 &load_result));
466 PumpLoop();
468 // Adding more messages should still fail.
469 for (int i = 0; i < kNumMessagesPerApp; ++i) {
470 mcs_proto::DataMessageStanza message;
471 message.set_from(kAppName);
472 message.set_category(kCategoryName);
473 EXPECT_FALSE(gcm_store->AddOutgoingMessage(
474 base::IntToString(i + kNumMessagesPerApp),
475 MCSMessage(message),
476 base::Bind(&GCMStoreImplTest::UpdateCallback,
477 base::Unretained(this))));
478 PumpLoop();
481 // Remove the existing messages.
482 for (int i = 0; i < kNumMessagesPerApp; ++i) {
483 gcm_store->RemoveOutgoingMessage(
484 base::IntToString(i),
485 base::Bind(&GCMStoreImplTest::UpdateCallback,
486 base::Unretained(this)));
487 PumpLoop();
490 // Successfully add new messages.
491 for (int i = 0; i < kNumMessagesPerApp; ++i) {
492 mcs_proto::DataMessageStanza message;
493 message.set_from(kAppName);
494 message.set_category(kCategoryName);
495 EXPECT_TRUE(gcm_store->AddOutgoingMessage(
496 base::IntToString(i + kNumMessagesPerApp),
497 MCSMessage(message),
498 base::Bind(&GCMStoreImplTest::UpdateCallback,
499 base::Unretained(this))));
500 PumpLoop();
504 // When the database is destroyed, all database updates should fail. At the
505 // same time, they per-app message counts should not go up, as failures should
506 // result in decrementing the counts.
507 TEST_F(GCMStoreImplTest, AddMessageAfterDestroy) {
508 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
509 scoped_ptr<GCMStore::LoadResult> load_result;
510 gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
511 base::Unretained(this),
512 &load_result));
513 PumpLoop();
514 gcm_store->Destroy(base::Bind(&GCMStoreImplTest::UpdateCallback,
515 base::Unretained(this)));
516 PumpLoop();
518 expected_success_ = false;
519 for (int i = 0; i < kNumMessagesPerApp * 2; ++i) {
520 mcs_proto::DataMessageStanza message;
521 message.set_from(kAppName);
522 message.set_category(kCategoryName);
523 // Because all adds are failing, none should hit the per-app message limits.
524 EXPECT_TRUE(gcm_store->AddOutgoingMessage(
525 base::IntToString(i),
526 MCSMessage(message),
527 base::Bind(&GCMStoreImplTest::UpdateCallback,
528 base::Unretained(this))));
529 PumpLoop();
533 TEST_F(GCMStoreImplTest, ReloadAfterClose) {
534 scoped_ptr<GCMStore> gcm_store(BuildGCMStore());
535 scoped_ptr<GCMStore::LoadResult> load_result;
536 gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
537 base::Unretained(this),
538 &load_result));
539 PumpLoop();
541 gcm_store->Close();
542 PumpLoop();
544 gcm_store->Load(base::Bind(&GCMStoreImplTest::LoadCallback,
545 base::Unretained(this),
546 &load_result));
547 PumpLoop();
550 } // namespace
552 } // namespace gcm