Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / web_resource / promo_resource_service_unittest.cc
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.
4
5 #include <utility>
6 #include <vector>
7
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"
30
31 namespace {
32
33 const char kDateFormat[] = "dd MMM yyyy HH:mm:ss zzzz";
34
35 bool YearFromNow(double* date_epoch, std::string* date_string) {
36   *date_epoch = (base::Time::Now() + base::TimeDelta::FromDays(365)).ToTimeT();
37
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;
44
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;
51
52   return base::UTF16ToUTF8(date_unicode_string.getBuffer(),
53                            static_cast<size_t>(date_unicode_string.length()),
54                            date_string);
55 }
56
57 }  // namespace
58
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) {}
65
66  protected:
67   ScopedTestingLocalState local_state_;
68   scoped_refptr<PromoResourceService> promo_resource_service_;
69   base::MessageLoop loop_;
70 };
71
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) {}
85
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));
94
95     std::vector<std::string> replacements;
96     replacements.push_back(year_from_now_string);
97
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);
102
103     base::DictionaryValue* dict = NULL;
104     value->GetAsDictionary(&dict);
105     ASSERT_TRUE(dict);
106     test_json_.reset(dict);
107
108     promo_type_ = NotificationPromo::NTP_NOTIFICATION_PROMO;
109     promo_text_ = promo_text;
110
111     start_ = start;
112     end_ = year_from_now_epoch;
113
114     num_groups_ = num_groups;
115     initial_segment_ = initial_segment;
116     increment_ = increment;
117     time_slice_ = time_slice;
118     max_group_ = max_group;
119
120     max_views_ = max_views;
121
122     closed_ = false;
123     received_notification_ = false;
124   }
125
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());
130
131     // Test the fields.
132     TestNotification();
133   }
134
135   void TestNotification() {
136     // Check values.
137     EXPECT_EQ(notification_promo_.promo_text_, promo_text_);
138
139     EXPECT_EQ(notification_promo_.start_, start_);
140     EXPECT_EQ(notification_promo_.end_, end_);
141
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_);
147
148     EXPECT_EQ(notification_promo_.max_views_, max_views_);
149     EXPECT_EQ(notification_promo_.closed_, closed_);
150
151     // Check group within bounds.
152     EXPECT_GE(notification_promo_.group_, 0);
153     EXPECT_LT(notification_promo_.group_, num_groups_);
154
155     // Views should be 0 for now.
156     EXPECT_EQ(notification_promo_.views_, 0);
157   }
158
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_);
164
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_);
191   }
192
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());
199     }
200
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());
205     }
206
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());
212     }
213     notification_promo_.WritePrefs();
214   }
215
216   void TestViews() {
217     notification_promo_.views_ = notification_promo_.max_views_ - 2;
218     notification_promo_.WritePrefs();
219
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());
229
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());
234     }
235
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());
240     }
241     new_promo.WritePrefs();
242   }
243
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());
249
250     NotificationPromo::HandleClosed(promo_type_);
251     new_promo.InitFromPrefs(promo_type_);
252     EXPECT_TRUE(new_promo.closed_);
253     EXPECT_FALSE(new_promo.CanShow());
254
255     new_promo.closed_ = false;
256     EXPECT_TRUE(new_promo.CanShow());
257     new_promo.WritePrefs();
258   }
259
260   void TestPromoText() {
261     notification_promo_.promo_text_.clear();
262     EXPECT_FALSE(notification_promo_.CanShow());
263
264     notification_promo_.promo_text_ = promo_text_;
265     EXPECT_TRUE(notification_promo_.CanShow());
266   }
267
268   void TestTime() {
269     const double now = base::Time::Now().ToDoubleT();
270     const double qhour = 15 * 60;
271
272     notification_promo_.group_ = 0;  // For simplicity.
273
274     notification_promo_.start_ = now - qhour;
275     notification_promo_.end_ = now + qhour;
276     EXPECT_TRUE(notification_promo_.CanShow());
277
278     // Start time has not arrived.
279     notification_promo_.start_ = now + qhour;
280     notification_promo_.end_ = now + qhour;
281     EXPECT_FALSE(notification_promo_.CanShow());
282
283     // End time has past.
284     notification_promo_.start_ = now - qhour;
285     notification_promo_.end_ = now - qhour;
286     EXPECT_FALSE(notification_promo_.CanShow());
287
288     notification_promo_.start_ = start_;
289     notification_promo_.end_ = end_;
290     EXPECT_TRUE(notification_promo_.CanShow());
291   }
292
293   void TestIncrement() {
294     const double now = base::Time::Now().ToDoubleT();
295     const double slice = 60;
296
297     notification_promo_.num_groups_ = 18;
298     notification_promo_.initial_segment_ = 5;
299     notification_promo_.increment_ = 3;
300     notification_promo_.time_slice_ = slice;
301
302     notification_promo_.start_ = now - 1;
303     notification_promo_.end_ = now + slice;
304
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());
310
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());
317
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());
324
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());
331
332     // Test last increment.
333     notification_promo_.start_ -= slice;
334     EXPECT_TRUE(notification_promo_.CanShow());
335   }
336
337   const NotificationPromo& promo() const { return notification_promo_; }
338
339  private:
340   NotificationPromo notification_promo_;
341   bool received_notification_;
342   scoped_ptr<base::DictionaryValue> test_json_;
343
344   NotificationPromo::PromoType promo_type_;
345   std::string promo_text_;
346
347   double start_;
348   double end_;
349
350   int num_groups_;
351   int initial_segment_;
352   int increment_;
353   int time_slice_;
354   int max_group_;
355
356   int max_views_;
357
358   bool closed_;
359 };
360
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;
368
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);
408
409   promo_test.InitPromoFromJson(true);
410
411   // Second time should not trigger a notification.
412   promo_test.InitPromoFromJson(false);
413
414   promo_test.TestInitFromPrefs();
415
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();
424 }
425
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;
430
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);
467
468   promo_test.InitPromoFromJson(true);
469   // Second time should not trigger a notification.
470   promo_test.InitPromoFromJson(false);
471   promo_test.TestInitFromPrefs();
472 }
473
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;
478
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);
521
522   promo_test.InitPromoFromJson(true);
523   // Second time should not trigger a notification.
524   promo_test.InitPromoFromJson(false);
525   promo_test.TestInitFromPrefs();
526 }
527
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(url::kHttpsScheme));
533   // TODO(achuith): Test this better.
534 }
535
536 #if defined(ENABLE_APP_LIST)
537 TEST_F(PromoResourceServiceTest, AppLauncherPromoTest) {
538   // Check that prefs are set correctly.
539   NotificationPromoTest promo_test;
540
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());
581 }
582 #endif