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.
4
5#include "base/strings/string_number_conversions.h"
6#include "google_apis/gcm/engine/gservices_settings.h"
7#include "google_apis/gcm/engine/registration_info.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10namespace gcm {
11
12namespace {
13
14const int64 kAlternativeCheckinInterval = 16 * 60 * 60;
15const char kAlternativeCheckinURL[] = "http://alternative.url/checkin";
16const char kAlternativeMCSHostname[] = "alternative.gcm.host";
17const int kAlternativeMCSSecurePort = 7777;
18const char kAlternativeRegistrationURL[] =
19    "http://alternative.url/registration";
20
21const int64 kDefaultCheckinInterval = 2 * 24 * 60 * 60;  // seconds = 2 days.
22const char kDefaultCheckinURL[] = "https://android.clients.google.com/checkin";
23const char kDefaultRegistrationURL[] =
24    "https://android.clients.google.com/c2dm/register3";
25const char kDefaultSettingsDigest[] =
26    "1-da39a3ee5e6b4b0d3255bfef95601890afd80709";
27const char kAlternativeSettingsDigest[] =
28    "1-7da4aa4eb38a8bd3e330e3751cc0899924499134";
29
30void AddSettingsToResponse(
31    checkin_proto::AndroidCheckinResponse& checkin_response,
32    const GServicesSettings::SettingsMap& settings,
33    bool settings_diff) {
34  for (GServicesSettings::SettingsMap::const_iterator iter = settings.begin();
35       iter != settings.end();
36       ++iter) {
37    checkin_proto::GservicesSetting* setting = checkin_response.add_setting();
38    setting->set_name(iter->first);
39    setting->set_value(iter->second);
40  }
41  checkin_response.set_settings_diff(settings_diff);
42}
43
44}  // namespace
45
46class GServicesSettingsTest : public testing::Test {
47 public:
48  GServicesSettingsTest();
49  virtual ~GServicesSettingsTest();
50
51  void CheckAllSetToDefault();
52
53  GServicesSettings& settings() {
54    return gservices_settings_;
55  }
56
57 private:
58  GServicesSettings gservices_settings_;
59};
60
61GServicesSettingsTest::GServicesSettingsTest()
62    : gservices_settings_() {
63}
64
65GServicesSettingsTest::~GServicesSettingsTest() {}
66
67void GServicesSettingsTest::CheckAllSetToDefault() {
68  EXPECT_EQ(base::TimeDelta::FromSeconds(kDefaultCheckinInterval),
69            settings().GetCheckinInterval());
70  EXPECT_EQ(GURL(kDefaultCheckinURL), settings().GetCheckinURL());
71  EXPECT_EQ(GURL("https://mtalk.google.com:5228"),
72            settings().GetMCSMainEndpoint());
73  EXPECT_EQ(GURL("https://mtalk.google.com:443"),
74            settings().GetMCSFallbackEndpoint());
75  EXPECT_EQ(GURL(kDefaultRegistrationURL), settings().GetRegistrationURL());
76}
77
78// Verifies default values of the G-services settings and settings digest.
79TEST_F(GServicesSettingsTest, DefaultSettingsAndDigest) {
80  CheckAllSetToDefault();
81  EXPECT_EQ(kDefaultSettingsDigest, settings().digest());
82  EXPECT_EQ(kDefaultSettingsDigest,
83            GServicesSettings::CalculateDigest(settings().settings_map()));
84}
85
86// Verifies digest calculation for the sample provided by protocol owners.
87TEST_F(GServicesSettingsTest, CalculateDigest) {
88  GServicesSettings::SettingsMap settings_map;
89  settings_map["android_id"] = "55XXXXXXXXXXXXXXXX0";
90  settings_map["checkin_interval"] = "86400";
91  settings_map["checkin_url"] =
92      "https://fake.address.google.com/canary/checkin";
93  settings_map["chrome_device"] = "1";
94  settings_map["device_country"] = "us";
95  settings_map["gcm_hostname"] = "fake.address.google.com";
96  settings_map["gcm_secure_port"] = "443";
97
98  EXPECT_EQ("1-33381ccd1cf5791dc0e6dfa234266fa9f1259197",
99            GServicesSettings::CalculateDigest(settings_map));
100}
101
102// Verifies that settings are not updated when load result is empty.
103TEST_F(GServicesSettingsTest, UpdateFromEmptyLoadResult) {
104  GCMStore::LoadResult result;
105  result.gservices_digest = "";
106  settings().UpdateFromLoadResult(result);
107
108  CheckAllSetToDefault();
109  EXPECT_EQ(kDefaultSettingsDigest, settings().digest());
110}
111
112// Verifies that settings are not when digest value does not match.
113TEST_F(GServicesSettingsTest, UpdateFromLoadResultWithSettingMissing) {
114  GCMStore::LoadResult result;
115  result.gservices_settings["checkin_internval"] = "100000";
116  result.gservices_digest = "digest_value";
117  settings().UpdateFromLoadResult(result);
118
119  CheckAllSetToDefault();
120  EXPECT_EQ(kDefaultSettingsDigest, settings().digest());
121}
122
123// Verifies that the settings are set correctly based on the load result.
124TEST_F(GServicesSettingsTest, UpdateFromLoadResult) {
125  GCMStore::LoadResult result;
126  result.gservices_settings["checkin_interval"] =
127      base::Int64ToString(kAlternativeCheckinInterval);
128  result.gservices_settings["checkin_url"] = kAlternativeCheckinURL;
129  result.gservices_settings["gcm_hostname"] = kAlternativeMCSHostname;
130  result.gservices_settings["gcm_secure_port"] =
131      base::IntToString(kAlternativeMCSSecurePort);
132  result.gservices_settings["gcm_registration_url"] =
133      kAlternativeRegistrationURL;
134  result.gservices_digest = kAlternativeSettingsDigest;
135  settings().UpdateFromLoadResult(result);
136
137  EXPECT_EQ(base::TimeDelta::FromSeconds(kAlternativeCheckinInterval),
138            settings().GetCheckinInterval());
139  EXPECT_EQ(GURL(kAlternativeCheckinURL), settings().GetCheckinURL());
140  EXPECT_EQ(GURL("https://alternative.gcm.host:7777"),
141            settings().GetMCSMainEndpoint());
142  EXPECT_EQ(GURL("https://alternative.gcm.host:443"),
143            settings().GetMCSFallbackEndpoint());
144  EXPECT_EQ(GURL(kAlternativeRegistrationURL), settings().GetRegistrationURL());
145  EXPECT_EQ(GServicesSettings::CalculateDigest(result.gservices_settings),
146            settings().digest());
147}
148
149// Verifies that the checkin interval is updated to minimum if the original
150// value is less than minimum.
151TEST_F(GServicesSettingsTest, CheckinResponseMinimumCheckinInterval) {
152  // Setting the checkin interval to less than minimum.
153  checkin_proto::AndroidCheckinResponse checkin_response;
154  GServicesSettings::SettingsMap new_settings;
155  new_settings["checkin_interval"] = "3600";
156  AddSettingsToResponse(checkin_response, new_settings, false);
157
158  EXPECT_TRUE(settings().UpdateFromCheckinResponse(checkin_response));
159
160  EXPECT_EQ(GServicesSettings::MinimumCheckinInterval(),
161            settings().GetCheckinInterval());
162  EXPECT_EQ(GServicesSettings::CalculateDigest(new_settings),
163            settings().digest());
164}
165
166// Verifies that default checkin interval can be selectively overwritten.
167TEST_F(GServicesSettingsTest, CheckinResponseUpdateCheckinInterval) {
168  checkin_proto::AndroidCheckinResponse checkin_response;
169  GServicesSettings::SettingsMap new_settings;
170  new_settings["checkin_interval"] = "86400";
171  AddSettingsToResponse(checkin_response, new_settings, false);
172
173  EXPECT_TRUE(settings().UpdateFromCheckinResponse(checkin_response));
174
175  // Only the checkin interval was updated:
176  EXPECT_EQ(base::TimeDelta::FromSeconds(86400),
177            settings().GetCheckinInterval());
178
179  // Other settings still set to default.
180  EXPECT_EQ(GURL("https://mtalk.google.com:5228"),
181            settings().GetMCSMainEndpoint());
182  EXPECT_EQ(GURL("https://mtalk.google.com:443"),
183            settings().GetMCSFallbackEndpoint());
184  EXPECT_EQ(GURL(kDefaultCheckinURL), settings().GetCheckinURL());
185  EXPECT_EQ(GURL(kDefaultRegistrationURL), settings().GetRegistrationURL());
186
187  EXPECT_EQ(GServicesSettings::CalculateDigest(new_settings),
188            settings().digest());
189}
190
191// Verifies that default registration URL can be selectively overwritten.
192TEST_F(GServicesSettingsTest, CheckinResponseUpdateRegistrationURL) {
193  checkin_proto::AndroidCheckinResponse checkin_response;
194  GServicesSettings::SettingsMap new_settings;
195  new_settings["gcm_registration_url"] = "https://new.registration.url";
196  AddSettingsToResponse(checkin_response, new_settings, false);
197
198  EXPECT_TRUE(settings().UpdateFromCheckinResponse(checkin_response));
199
200  // Only the registration URL was updated:
201  EXPECT_EQ(GURL("https://new.registration.url"),
202            settings().GetRegistrationURL());
203
204  // Other settings still set to default.
205  EXPECT_EQ(base::TimeDelta::FromSeconds(kDefaultCheckinInterval),
206            settings().GetCheckinInterval());
207  EXPECT_EQ(GURL("https://mtalk.google.com:5228"),
208            settings().GetMCSMainEndpoint());
209  EXPECT_EQ(GURL("https://mtalk.google.com:443"),
210            settings().GetMCSFallbackEndpoint());
211  EXPECT_EQ(GURL(kDefaultCheckinURL), settings().GetCheckinURL());
212
213  EXPECT_EQ(GServicesSettings::CalculateDigest(new_settings),
214            settings().digest());
215}
216
217// Verifies that default checkin URL can be selectively overwritten.
218TEST_F(GServicesSettingsTest, CheckinResponseUpdateCheckinURL) {
219  checkin_proto::AndroidCheckinResponse checkin_response;
220  GServicesSettings::SettingsMap new_settings;
221  new_settings["checkin_url"] = "https://new.checkin.url";
222  AddSettingsToResponse(checkin_response, new_settings, false);
223
224  EXPECT_TRUE(settings().UpdateFromCheckinResponse(checkin_response));
225
226  // Only the checkin URL was updated:
227  EXPECT_EQ(GURL("https://new.checkin.url"), settings().GetCheckinURL());
228
229  // Other settings still set to default.
230  EXPECT_EQ(base::TimeDelta::FromSeconds(kDefaultCheckinInterval),
231            settings().GetCheckinInterval());
232  EXPECT_EQ(GURL("https://mtalk.google.com:5228"),
233            settings().GetMCSMainEndpoint());
234  EXPECT_EQ(GURL("https://mtalk.google.com:443"),
235            settings().GetMCSFallbackEndpoint());
236  EXPECT_EQ(GURL(kDefaultRegistrationURL), settings().GetRegistrationURL());
237
238  EXPECT_EQ(GServicesSettings::CalculateDigest(new_settings),
239            settings().digest());
240}
241
242// Verifies that default MCS hostname can be selectively overwritten.
243TEST_F(GServicesSettingsTest, CheckinResponseUpdateMCSHostname) {
244  checkin_proto::AndroidCheckinResponse checkin_response;
245  GServicesSettings::SettingsMap new_settings;
246  new_settings["gcm_hostname"] = "new.gcm.hostname";
247  AddSettingsToResponse(checkin_response, new_settings, false);
248
249  EXPECT_TRUE(settings().UpdateFromCheckinResponse(checkin_response));
250
251  // Only the MCS endpoints were updated:
252  EXPECT_EQ(GURL("https://new.gcm.hostname:5228"),
253            settings().GetMCSMainEndpoint());
254  EXPECT_EQ(GURL("https://new.gcm.hostname:443"),
255            settings().GetMCSFallbackEndpoint());
256
257  // Other settings still set to default.
258  EXPECT_EQ(base::TimeDelta::FromSeconds(kDefaultCheckinInterval),
259            settings().GetCheckinInterval());
260  EXPECT_EQ(GURL(kDefaultCheckinURL), settings().GetCheckinURL());
261  EXPECT_EQ(GURL(kDefaultRegistrationURL), settings().GetRegistrationURL());
262
263  EXPECT_EQ(GServicesSettings::CalculateDigest(new_settings),
264            settings().digest());
265}
266
267// Verifies that default MCS secure port can be selectively overwritten.
268TEST_F(GServicesSettingsTest, CheckinResponseUpdateMCSSecurePort) {
269  checkin_proto::AndroidCheckinResponse checkin_response;
270  GServicesSettings::SettingsMap new_settings;
271  new_settings["gcm_secure_port"] = "5229";
272  AddSettingsToResponse(checkin_response, new_settings, false);
273
274  EXPECT_TRUE(settings().UpdateFromCheckinResponse(checkin_response));
275
276  // Only the main MCS endpoint was updated:
277  EXPECT_EQ(GURL("https://mtalk.google.com:5229"),
278            settings().GetMCSMainEndpoint());
279
280  // Other settings still set to default.
281  EXPECT_EQ(base::TimeDelta::FromSeconds(kDefaultCheckinInterval),
282            settings().GetCheckinInterval());
283  EXPECT_EQ(GURL(kDefaultCheckinURL), settings().GetCheckinURL());
284  EXPECT_EQ(GURL("https://mtalk.google.com:443"),
285            settings().GetMCSFallbackEndpoint());
286  EXPECT_EQ(GURL(kDefaultRegistrationURL), settings().GetRegistrationURL());
287
288  EXPECT_EQ(GServicesSettings::CalculateDigest(new_settings),
289            settings().digest());
290}
291
292// Update from checkin response should also do incremental update for both cases
293// where some settings are removed or added.
294TEST_F(GServicesSettingsTest, UpdateFromCheckinResponseSettingsDiff) {
295  checkin_proto::AndroidCheckinResponse checkin_response;
296
297  // Only the new settings will be included in the response with settings diff.
298  GServicesSettings::SettingsMap settings_diff;
299  settings_diff["new_setting_1"] = "new_setting_1_value";
300  settings_diff["new_setting_2"] = "new_setting_2_value";
301  settings_diff["gcm_secure_port"] = "5229";
302
303  // Full settings are necessary to calculate digest.
304  GServicesSettings::SettingsMap full_settings(settings_diff);
305  std::string digest = GServicesSettings::CalculateDigest(full_settings);
306
307  checkin_response.Clear();
308  AddSettingsToResponse(checkin_response, settings_diff, true);
309  EXPECT_TRUE(settings().UpdateFromCheckinResponse(checkin_response));
310  EXPECT_EQ(full_settings, settings().settings_map());
311  // Default setting overwritten by settings diff.
312  EXPECT_EQ(GURL("https://mtalk.google.com:5229"),
313            settings().GetMCSMainEndpoint());
314
315  // Setting up diff removing some of the values (including default setting).
316  settings_diff.clear();
317  settings_diff["delete_new_setting_1"] = "";
318  settings_diff["delete_gcm_secure_port"] = "";
319  settings_diff["new_setting_3"] = "new_setting_3_value";
320
321  // Updating full settings to calculate digest.
322  full_settings.erase(full_settings.find("new_setting_1"));
323  full_settings.erase(full_settings.find("gcm_secure_port"));
324  full_settings["new_setting_3"] = "new_setting_3_value";
325  digest = GServicesSettings::CalculateDigest(full_settings);
326
327  checkin_response.Clear();
328  AddSettingsToResponse(checkin_response, settings_diff, true);
329  EXPECT_TRUE(settings().UpdateFromCheckinResponse(checkin_response));
330  EXPECT_EQ(full_settings, settings().settings_map());
331  // Default setting back to norm.
332  EXPECT_EQ(GURL("https://mtalk.google.com:5228"),
333            settings().GetMCSMainEndpoint());
334}
335
336}  // namespace gcm
337