Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / web_resource / promo_resource_service_unittest.cc
blob80ed3dcde140b99dcba576b917ab45ce53102015
1 // Copyright (c) 2012 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 <utility>
6 #include <vector>
8 #include "base/json/json_reader.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "base/values.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/prefs/browser_prefs.h"
19 #include "chrome/browser/web_resource/notification_promo.h"
20 #include "chrome/browser/web_resource/promo_resource_service.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/common/url_constants.h"
23 #include "chrome/test/base/scoped_testing_local_state.h"
24 #include "chrome/test/base/testing_browser_process.h"
25 #include "content/public/browser/notification_registrar.h"
26 #include "content/public/browser/notification_service.h"
27 #include "net/url_request/test_url_fetcher_factory.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "third_party/icu/source/i18n/unicode/smpdtfmt.h"
31 namespace {
33 const char kDateFormat[] = "dd MMM yyyy HH:mm:ss zzz";
35 bool YearFromNow(double* date_epoch, std::string* date_string) {
36 *date_epoch = (base::Time::Now() + base::TimeDelta::FromDays(365)).ToTimeT();
38 UErrorCode status = U_ZERO_ERROR;
39 icu::SimpleDateFormat simple_formatter(icu::UnicodeString(kDateFormat),
40 icu::Locale("en_US"),
41 status);
42 if (!U_SUCCESS(status))
43 return false;
45 icu::UnicodeString date_unicode_string;
46 simple_formatter.format(static_cast<UDate>(*date_epoch * 1000),
47 date_unicode_string,
48 status);
49 if (!U_SUCCESS(status))
50 return false;
52 return base::UTF16ToUTF8(date_unicode_string.getBuffer(),
53 static_cast<size_t>(date_unicode_string.length()),
54 date_string);
57 } // namespace
59 class PromoResourceServiceTest : public testing::Test {
60 public:
61 // |promo_resource_service_| must be created after |local_state_|.
62 PromoResourceServiceTest()
63 : local_state_(TestingBrowserProcess::GetGlobal()),
64 promo_resource_service_(new PromoResourceService) {}
66 protected:
67 ScopedTestingLocalState local_state_;
68 scoped_refptr<PromoResourceService> promo_resource_service_;
69 base::MessageLoop loop_;
72 class NotificationPromoTest {
73 public:
74 NotificationPromoTest()
75 : received_notification_(false),
76 start_(0.0),
77 end_(0.0),
78 num_groups_(0),
79 initial_segment_(0),
80 increment_(1),
81 time_slice_(0),
82 max_group_(0),
83 max_views_(0),
84 closed_(false) {}
86 void Init(const std::string& json,
87 const std::string& promo_text,
88 double start,
89 int num_groups, int initial_segment, int increment,
90 int time_slice, int max_group, int max_views) {
91 double year_from_now_epoch;
92 std::string year_from_now_string;
93 ASSERT_TRUE(YearFromNow(&year_from_now_epoch, &year_from_now_string));
95 std::vector<std::string> replacements;
96 replacements.push_back(year_from_now_string);
98 std::string json_with_end_date(
99 ReplaceStringPlaceholders(json, replacements, NULL));
100 base::Value* value(base::JSONReader::Read(json_with_end_date));
101 ASSERT_TRUE(value);
103 base::DictionaryValue* dict = NULL;
104 value->GetAsDictionary(&dict);
105 ASSERT_TRUE(dict);
106 test_json_.reset(dict);
108 promo_type_ = NotificationPromo::NTP_NOTIFICATION_PROMO;
109 promo_text_ = promo_text;
111 start_ = start;
112 end_ = year_from_now_epoch;
114 num_groups_ = num_groups;
115 initial_segment_ = initial_segment;
116 increment_ = increment;
117 time_slice_ = time_slice;
118 max_group_ = max_group;
120 max_views_ = max_views;
122 closed_ = false;
123 received_notification_ = false;
126 void InitPromoFromJson(bool should_receive_notification) {
127 notification_promo_.InitFromJson(*test_json_, promo_type_);
128 EXPECT_EQ(should_receive_notification,
129 notification_promo_.new_notification());
131 // Test the fields.
132 TestNotification();
135 void TestNotification() {
136 // Check values.
137 EXPECT_EQ(notification_promo_.promo_text_, promo_text_);
139 EXPECT_EQ(notification_promo_.start_, start_);
140 EXPECT_EQ(notification_promo_.end_, end_);
142 EXPECT_EQ(notification_promo_.num_groups_, num_groups_);
143 EXPECT_EQ(notification_promo_.initial_segment_, initial_segment_);
144 EXPECT_EQ(notification_promo_.increment_, increment_);
145 EXPECT_EQ(notification_promo_.time_slice_, time_slice_);
146 EXPECT_EQ(notification_promo_.max_group_, max_group_);
148 EXPECT_EQ(notification_promo_.max_views_, max_views_);
149 EXPECT_EQ(notification_promo_.closed_, closed_);
151 // Check group within bounds.
152 EXPECT_GE(notification_promo_.group_, 0);
153 EXPECT_LT(notification_promo_.group_, num_groups_);
155 // Views should be 0 for now.
156 EXPECT_EQ(notification_promo_.views_, 0);
159 // Create a new NotificationPromo from prefs and compare to current
160 // notification.
161 void TestInitFromPrefs() {
162 NotificationPromo prefs_notification_promo;
163 prefs_notification_promo.InitFromPrefs(promo_type_);
165 EXPECT_EQ(notification_promo_.prefs_,
166 prefs_notification_promo.prefs_);
167 EXPECT_EQ(notification_promo_.promo_text_,
168 prefs_notification_promo.promo_text_);
169 EXPECT_EQ(notification_promo_.start_,
170 prefs_notification_promo.start_);
171 EXPECT_EQ(notification_promo_.end_,
172 prefs_notification_promo.end_);
173 EXPECT_EQ(notification_promo_.num_groups_,
174 prefs_notification_promo.num_groups_);
175 EXPECT_EQ(notification_promo_.initial_segment_,
176 prefs_notification_promo.initial_segment_);
177 EXPECT_EQ(notification_promo_.increment_,
178 prefs_notification_promo.increment_);
179 EXPECT_EQ(notification_promo_.time_slice_,
180 prefs_notification_promo.time_slice_);
181 EXPECT_EQ(notification_promo_.max_group_,
182 prefs_notification_promo.max_group_);
183 EXPECT_EQ(notification_promo_.max_views_,
184 prefs_notification_promo.max_views_);
185 EXPECT_EQ(notification_promo_.group_,
186 prefs_notification_promo.group_);
187 EXPECT_EQ(notification_promo_.views_,
188 prefs_notification_promo.views_);
189 EXPECT_EQ(notification_promo_.closed_,
190 prefs_notification_promo.closed_);
193 void TestGroup() {
194 // Test out of range groups.
195 const int incr = num_groups_ / 20;
196 for (int i = max_group_; i < num_groups_; i += incr) {
197 notification_promo_.group_ = i;
198 EXPECT_FALSE(notification_promo_.CanShow());
201 // Test in-range groups.
202 for (int i = 0; i < max_group_; i += incr) {
203 notification_promo_.group_ = i;
204 EXPECT_TRUE(notification_promo_.CanShow());
207 // When max_group_ is 0, all groups pass.
208 notification_promo_.max_group_ = 0;
209 for (int i = 0; i < num_groups_; i += incr) {
210 notification_promo_.group_ = i;
211 EXPECT_TRUE(notification_promo_.CanShow());
213 notification_promo_.WritePrefs();
216 void TestViews() {
217 notification_promo_.views_ = notification_promo_.max_views_ - 2;
218 notification_promo_.WritePrefs();
220 NotificationPromo::HandleViewed(promo_type_);
221 NotificationPromo new_promo;
222 new_promo.InitFromPrefs(promo_type_);
223 EXPECT_EQ(new_promo.max_views_ - 1, new_promo.views_);
224 EXPECT_TRUE(new_promo.CanShow());
225 NotificationPromo::HandleViewed(promo_type_);
226 new_promo.InitFromPrefs(promo_type_);
227 EXPECT_EQ(new_promo.max_views_, new_promo.views_);
228 EXPECT_FALSE(new_promo.CanShow());
230 // Test out of range views.
231 for (int i = max_views_; i < max_views_ * 2; ++i) {
232 new_promo.views_ = i;
233 EXPECT_FALSE(new_promo.CanShow());
236 // Test in range views.
237 for (int i = 0; i < max_views_; ++i) {
238 new_promo.views_ = i;
239 EXPECT_TRUE(new_promo.CanShow());
241 new_promo.WritePrefs();
244 void TestClosed() {
245 NotificationPromo new_promo;
246 new_promo.InitFromPrefs(promo_type_);
247 EXPECT_FALSE(new_promo.closed_);
248 EXPECT_TRUE(new_promo.CanShow());
250 NotificationPromo::HandleClosed(promo_type_);
251 new_promo.InitFromPrefs(promo_type_);
252 EXPECT_TRUE(new_promo.closed_);
253 EXPECT_FALSE(new_promo.CanShow());
255 new_promo.closed_ = false;
256 EXPECT_TRUE(new_promo.CanShow());
257 new_promo.WritePrefs();
260 void TestPromoText() {
261 notification_promo_.promo_text_.clear();
262 EXPECT_FALSE(notification_promo_.CanShow());
264 notification_promo_.promo_text_ = promo_text_;
265 EXPECT_TRUE(notification_promo_.CanShow());
268 void TestTime() {
269 const double now = base::Time::Now().ToDoubleT();
270 const double qhour = 15 * 60;
272 notification_promo_.group_ = 0; // For simplicity.
274 notification_promo_.start_ = now - qhour;
275 notification_promo_.end_ = now + qhour;
276 EXPECT_TRUE(notification_promo_.CanShow());
278 // Start time has not arrived.
279 notification_promo_.start_ = now + qhour;
280 notification_promo_.end_ = now + qhour;
281 EXPECT_FALSE(notification_promo_.CanShow());
283 // End time has past.
284 notification_promo_.start_ = now - qhour;
285 notification_promo_.end_ = now - qhour;
286 EXPECT_FALSE(notification_promo_.CanShow());
288 notification_promo_.start_ = start_;
289 notification_promo_.end_ = end_;
290 EXPECT_TRUE(notification_promo_.CanShow());
293 void TestIncrement() {
294 const double now = base::Time::Now().ToDoubleT();
295 const double slice = 60;
297 notification_promo_.num_groups_ = 18;
298 notification_promo_.initial_segment_ = 5;
299 notification_promo_.increment_ = 3;
300 notification_promo_.time_slice_ = slice;
302 notification_promo_.start_ = now - 1;
303 notification_promo_.end_ = now + slice;
305 // Test initial segment.
306 notification_promo_.group_ = 4;
307 EXPECT_TRUE(notification_promo_.CanShow());
308 notification_promo_.group_ = 5;
309 EXPECT_FALSE(notification_promo_.CanShow());
311 // Test first increment.
312 notification_promo_.start_ -= slice;
313 notification_promo_.group_ = 7;
314 EXPECT_TRUE(notification_promo_.CanShow());
315 notification_promo_.group_ = 8;
316 EXPECT_FALSE(notification_promo_.CanShow());
318 // Test second increment.
319 notification_promo_.start_ -= slice;
320 notification_promo_.group_ = 10;
321 EXPECT_TRUE(notification_promo_.CanShow());
322 notification_promo_.group_ = 11;
323 EXPECT_FALSE(notification_promo_.CanShow());
325 // Test penultimate increment.
326 notification_promo_.start_ -= 2 * slice;
327 notification_promo_.group_ = 16;
328 EXPECT_TRUE(notification_promo_.CanShow());
329 notification_promo_.group_ = 17;
330 EXPECT_FALSE(notification_promo_.CanShow());
332 // Test last increment.
333 notification_promo_.start_ -= slice;
334 EXPECT_TRUE(notification_promo_.CanShow());
337 const NotificationPromo& promo() const { return notification_promo_; }
339 private:
340 NotificationPromo notification_promo_;
341 bool received_notification_;
342 scoped_ptr<base::DictionaryValue> test_json_;
344 NotificationPromo::PromoType promo_type_;
345 std::string promo_text_;
347 double start_;
348 double end_;
350 int num_groups_;
351 int initial_segment_;
352 int increment_;
353 int time_slice_;
354 int max_group_;
356 int max_views_;
358 bool closed_;
361 // Test that everything gets parsed correctly, notifications are sent,
362 // and CanShow() is handled correctly under variety of conditions.
363 // Additionally, test that the first string in |strings| is used if
364 // no payload.promo_short_message is specified in the JSON response.
365 TEST_F(PromoResourceServiceTest, NotificationPromoTest) {
366 // Check that prefs are set correctly.
367 NotificationPromoTest promo_test;
369 // Set up start date and promo line in a Dictionary as if parsed from the
370 // service. date[0].end is replaced with a date 1 year in the future.
371 promo_test.Init("{"
372 " \"ntp_notification_promo\": ["
373 " {"
374 " \"date\":"
375 " ["
376 " {"
377 " \"start\":\"3 Aug 1999 9:26:06 GMT\","
378 " \"end\":\"$1\""
379 " }"
380 " ],"
381 " \"strings\":"
382 " {"
383 " \"NTP4_HOW_DO_YOU_FEEL_ABOUT_CHROME\":"
384 " \"What do you think of Chrome?\""
385 " },"
386 " \"grouping\":"
387 " {"
388 " \"buckets\":1000,"
389 " \"segment\":200,"
390 " \"increment\":100,"
391 " \"increment_frequency\":3600,"
392 " \"increment_max\":400"
393 " },"
394 " \"payload\":"
395 " {"
396 " \"days_active\":7,"
397 " \"install_age_days\":21"
398 " },"
399 " \"max_views\":30"
400 " }"
401 " ]"
402 "}",
403 "What do you think of Chrome?",
404 // The starting date is in 1999 to make tests pass
405 // on Android devices with incorrect or unset date/time.
406 933672366, // unix epoch for 3 Aug 1999 9:26:06 GMT.
407 1000, 200, 100, 3600, 400, 30);
409 promo_test.InitPromoFromJson(true);
411 // Second time should not trigger a notification.
412 promo_test.InitPromoFromJson(false);
414 promo_test.TestInitFromPrefs();
416 // Test various conditions of CanShow.
417 // TestGroup Has the side effect of setting us to a passing group.
418 promo_test.TestGroup();
419 promo_test.TestViews();
420 promo_test.TestClosed();
421 promo_test.TestPromoText();
422 promo_test.TestTime();
423 promo_test.TestIncrement();
426 // Test that payload.promo_message_short is used if present.
427 TEST_F(PromoResourceServiceTest, NotificationPromoCompatNoStringsTest) {
428 // Check that prefs are set correctly.
429 NotificationPromoTest promo_test;
431 // Set up start date and promo line in a Dictionary as if parsed from the
432 // service. date[0].end is replaced with a date 1 year in the future.
433 promo_test.Init("{"
434 " \"ntp_notification_promo\": ["
435 " {"
436 " \"date\":"
437 " ["
438 " {"
439 " \"start\":\"3 Aug 1999 9:26:06 GMT\","
440 " \"end\":\"$1\""
441 " }"
442 " ],"
443 " \"grouping\":"
444 " {"
445 " \"buckets\":1000,"
446 " \"segment\":200,"
447 " \"increment\":100,"
448 " \"increment_frequency\":3600,"
449 " \"increment_max\":400"
450 " },"
451 " \"payload\":"
452 " {"
453 " \"promo_message_short\":"
454 " \"What do you think of Chrome?\","
455 " \"days_active\":7,"
456 " \"install_age_days\":21"
457 " },"
458 " \"max_views\":30"
459 " }"
460 " ]"
461 "}",
462 "What do you think of Chrome?",
463 // The starting date is in 1999 to make tests pass
464 // on Android devices with incorrect or unset date/time.
465 933672366, // unix epoch for 3 Aug 1999 9:26:06 GMT.
466 1000, 200, 100, 3600, 400, 30);
468 promo_test.InitPromoFromJson(true);
469 // Second time should not trigger a notification.
470 promo_test.InitPromoFromJson(false);
471 promo_test.TestInitFromPrefs();
474 // Test that strings.|payload.promo_message_short| is used if present.
475 TEST_F(PromoResourceServiceTest, NotificationPromoCompatPayloadStringsTest) {
476 // Check that prefs are set correctly.
477 NotificationPromoTest promo_test;
479 // Set up start date and promo line in a Dictionary as if parsed from the
480 // service. date[0].end is replaced with a date 1 year in the future.
481 promo_test.Init("{"
482 " \"ntp_notification_promo\": ["
483 " {"
484 " \"date\":"
485 " ["
486 " {"
487 " \"start\":\"3 Aug 1999 9:26:06 GMT\","
488 " \"end\":\"$1\""
489 " }"
490 " ],"
491 " \"grouping\":"
492 " {"
493 " \"buckets\":1000,"
494 " \"segment\":200,"
495 " \"increment\":100,"
496 " \"increment_frequency\":3600,"
497 " \"increment_max\":400"
498 " },"
499 " \"strings\":"
500 " {"
501 " \"bogus\":\"string\","
502 " \"GOOD_STRING\":"
503 " \"What do you think of Chrome?\""
504 " },"
505 " \"payload\":"
506 " {"
507 " \"promo_message_short\":"
508 " \"GOOD_STRING\","
509 " \"days_active\":7,"
510 " \"install_age_days\":21"
511 " },"
512 " \"max_views\":30"
513 " }"
514 " ]"
515 "}",
516 "What do you think of Chrome?",
517 // The starting date is in 1999 to make tests pass
518 // on Android devices with incorrect or unset date/time.
519 933672366, // unix epoch for 3 Aug 1999 9:26:06 GMT.
520 1000, 200, 100, 3600, 400, 30);
522 promo_test.InitPromoFromJson(true);
523 // Second time should not trigger a notification.
524 promo_test.InitPromoFromJson(false);
525 promo_test.TestInitFromPrefs();
528 TEST_F(PromoResourceServiceTest, PromoServerURLTest) {
529 GURL promo_server_url = NotificationPromo::PromoServerURL();
530 EXPECT_FALSE(promo_server_url.is_empty());
531 EXPECT_TRUE(promo_server_url.is_valid());
532 EXPECT_TRUE(promo_server_url.SchemeIs(content::kHttpsScheme));
533 // TODO(achuith): Test this better.
536 #if defined(ENABLE_APP_LIST)
537 TEST_F(PromoResourceServiceTest, AppLauncherPromoTest) {
538 // Check that prefs are set correctly.
539 NotificationPromoTest promo_test;
541 // Set up start date and promo line in a Dictionary as if parsed from the
542 // service. date[0].end is replaced with a date 1 year in the future.
543 promo_test.Init("{"
544 " \"ntp_notification_promo\": ["
545 " {"
546 " \"date\":"
547 " ["
548 " {"
549 " \"start\":\"3 Aug 1999 9:26:06 GMT\","
550 " \"end\":\"$1\""
551 " }"
552 " ],"
553 " \"grouping\":"
554 " {"
555 " \"buckets\":1000,"
556 " \"segment\":200,"
557 " \"increment\":100,"
558 " \"increment_frequency\":3600,"
559 " \"increment_max\":400"
560 " },"
561 " \"payload\":"
562 " {"
563 " \"promo_message_short\":"
564 " \"What do you think of Chrome?\","
565 " \"days_active\":7,"
566 " \"install_age_days\":21,"
567 " \"is_app_launcher_promo\":true"
568 " },"
569 " \"max_views\":30"
570 " }"
571 " ]"
572 "}",
573 "What do you think of Chrome?",
574 // The starting date is in 1999 to make tests pass
575 // on Android devices with incorrect or unset date/time.
576 933672366, // unix epoch for 3 Aug 1999 9:26:06 GMT.
577 1000, 200, 100, 3600, 400, 30);
578 promo_test.InitPromoFromJson(true);
579 local_state_.Get()->SetBoolean(prefs::kAppLauncherIsEnabled, true);
580 EXPECT_FALSE(promo_test.promo().CanShow());
582 #endif