1// Copyright (c) 2013 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 <map>
6#include <string>
7
8#include "base/command_line.h"
9#include "base/message_loop/message_loop.h"
10#include "base/strings/string_number_conversions.h"
11#include "base/strings/string_util.h"
12#include "base/strings/utf_string_conversions.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/notifications/message_center_notification_manager.h"
15#include "chrome/browser/notifications/notification.h"
16#include "chrome/browser/notifications/notification_ui_manager.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/ui/browser.h"
19#include "chrome/test/base/in_process_browser_test.h"
20#include "chrome/test/base/test_switches.h"
21#include "ui/message_center/message_center.h"
22#include "ui/message_center/message_center_types.h"
23
24class TestAddObserver : public message_center::MessageCenterObserver {
25 public:
26  explicit TestAddObserver(message_center::MessageCenter* message_center)
27      : message_center_(message_center) {
28    message_center_->AddObserver(this);
29  }
30
31  virtual ~TestAddObserver() { message_center_->RemoveObserver(this); }
32
33  virtual void OnNotificationAdded(const std::string& id) OVERRIDE {
34    std::string log = logs_[id];
35    if (log != "")
36      log += "_";
37    logs_[id] = log + "add-" + id;
38  }
39
40  virtual void OnNotificationUpdated(const std::string& id) OVERRIDE {
41    std::string log = logs_[id];
42    if (log != "")
43      log += "_";
44    logs_[id] = log + "update-" + id;
45  }
46
47  const std::string log(const std::string& id) { return logs_[id]; }
48  void reset_logs() { logs_.clear(); }
49
50 private:
51  std::map<std::string, std::string> logs_;
52  message_center::MessageCenter* message_center_;
53};
54
55class MessageCenterNotificationsTest : public InProcessBrowserTest {
56 public:
57  MessageCenterNotificationsTest() {}
58
59  MessageCenterNotificationManager* manager() {
60    return static_cast<MessageCenterNotificationManager*>(
61        g_browser_process->notification_ui_manager());
62  }
63
64  message_center::MessageCenter* message_center() {
65    return g_browser_process->message_center();
66  }
67
68  Profile* profile() { return browser()->profile(); }
69
70  class TestDelegate : public NotificationDelegate {
71   public:
72    explicit TestDelegate(const std::string& id) : id_(id) {}
73
74    virtual void Display() OVERRIDE { log_ += "Display_"; }
75    virtual void Error() OVERRIDE { log_ += "Error_"; }
76    virtual void Close(bool by_user) OVERRIDE {
77      log_ += "Close_";
78      log_ += ( by_user ? "by_user_" : "programmatically_");
79    }
80    virtual void Click() OVERRIDE { log_ += "Click_"; }
81    virtual void ButtonClick(int button_index) OVERRIDE {
82      log_ += "ButtonClick_";
83      log_ += base::IntToString(button_index) + "_";
84    }
85    virtual std::string id() const OVERRIDE { return id_; }
86    virtual content::WebContents* GetWebContents() const OVERRIDE {
87      return NULL;
88    }
89
90    const std::string& log() { return log_; }
91
92   private:
93    virtual ~TestDelegate() {}
94    std::string id_;
95    std::string log_;
96
97    DISALLOW_COPY_AND_ASSIGN(TestDelegate);
98  };
99
100  Notification CreateTestNotification(const std::string& id,
101                                      TestDelegate** delegate = NULL) {
102    TestDelegate* new_delegate = new TestDelegate(id);
103    if (delegate) {
104      *delegate = new_delegate;
105      new_delegate->AddRef();
106    }
107
108    return Notification(GURL("chrome-test://testing/"),
109                        GURL(),
110                        base::ASCIIToUTF16("title"),
111                        base::ASCIIToUTF16("message"),
112                        blink::WebTextDirectionDefault,
113                        base::UTF8ToUTF16("chrome-test://testing/"),
114                        base::UTF8ToUTF16("REPLACE-ME"),
115                        new_delegate);
116  }
117
118  Notification CreateRichTestNotification(const std::string& id,
119                                          TestDelegate** delegate = NULL) {
120    TestDelegate* new_delegate = new TestDelegate(id);
121    if (delegate) {
122      *delegate = new_delegate;
123      new_delegate->AddRef();
124    }
125
126    message_center::RichNotificationData data;
127
128    return Notification(message_center::NOTIFICATION_TYPE_BASE_FORMAT,
129                        GURL("chrome-test://testing/"),
130                        base::ASCIIToUTF16("title"),
131                        base::ASCIIToUTF16("message"),
132                        gfx::Image(),
133                        blink::WebTextDirectionDefault,
134                        message_center::NotifierId(
135                            message_center::NotifierId::APPLICATION,
136                            "extension_id"),
137                        base::UTF8ToUTF16("chrome-test://testing/"),
138                        base::UTF8ToUTF16("REPLACE-ME"),
139                        data,
140                        new_delegate);
141  }
142};
143
144// TODO(rsesek): Implement Message Center on Mac and get these tests passing
145// for real. http://crbug.com/179904
146#if !defined(OS_MACOSX)
147
148IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, RetrieveBaseParts) {
149  EXPECT_TRUE(manager());
150  EXPECT_TRUE(message_center());
151}
152
153IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, BasicAddCancel) {
154#if defined(OS_WIN) && defined(USE_ASH)
155  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
156  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
157    return;
158#endif
159
160  // Someone may create system notifications like "you're in multi-profile
161  // mode..." or something which may change the expectation.
162  // TODO(mukai): move this to SetUpOnMainThread() after fixing the side-effect
163  // of canceling animation which prevents some Displayed() event.
164  manager()->CancelAll();
165  manager()->Add(CreateTestNotification("hey"), profile());
166  EXPECT_EQ(1u, message_center()->NotificationCount());
167  manager()->CancelById("hey");
168  EXPECT_EQ(0u, message_center()->NotificationCount());
169}
170
171IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, BasicDelegate) {
172#if defined(OS_WIN) && defined(USE_ASH)
173  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
174  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
175    return;
176#endif
177
178  TestDelegate* delegate;
179  manager()->Add(CreateTestNotification("hey", &delegate), profile());
180  // Verify that delegate accumulated correct log of events.
181  EXPECT_EQ("Display_", delegate->log());
182  manager()->CancelById("hey");
183  // Verify that delegate accumulated correct log of events.
184  EXPECT_EQ("Display_Close_programmatically_", delegate->log());
185  delegate->Release();
186}
187
188IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, ButtonClickedDelegate) {
189#if defined(OS_WIN) && defined(USE_ASH)
190  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
191  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
192    return;
193#endif
194
195  TestDelegate* delegate;
196  manager()->Add(CreateTestNotification("n", &delegate), profile());
197  message_center()->ClickOnNotificationButton("n", 1);
198  // Verify that delegate accumulated correct log of events.
199  EXPECT_EQ("Display_ButtonClick_1_", delegate->log());
200  delegate->Release();
201}
202
203IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
204                       UpdateExistingNotification) {
205#if defined(OS_WIN) && defined(USE_ASH)
206  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
207  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
208    return;
209#endif
210
211  TestDelegate* delegate;
212  manager()->Add(CreateTestNotification("n", &delegate), profile());
213  TestDelegate* delegate2;
214  manager()->Add(CreateRichTestNotification("n", &delegate2), profile());
215
216  manager()->CancelById("n");
217  EXPECT_EQ("Display_", delegate->log());
218  EXPECT_EQ("Close_programmatically_", delegate2->log());
219
220  delegate->Release();
221  delegate2->Release();
222}
223
224IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, QueueWhenCenterVisible) {
225#if defined(OS_WIN) && defined(USE_ASH)
226  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
227  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
228    return;
229#endif
230
231  TestAddObserver observer(message_center());
232
233  TestDelegate* delegate;
234  TestDelegate* delegate2;
235
236  manager()->Add(CreateTestNotification("n", &delegate), profile());
237  message_center()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
238  manager()->Add(CreateTestNotification("n2", &delegate2), profile());
239
240  // 'update-n' should happen since SetVisibility updates is_read status of n.
241  // TODO(mukai): fix event handling to happen update-n just once.
242  EXPECT_EQ("add-n_update-n_update-n", observer.log("n"));
243
244  message_center()->SetVisibility(message_center::VISIBILITY_TRANSIENT);
245
246  EXPECT_EQ("add-n2", observer.log("n2"));
247
248  delegate->Release();
249  delegate2->Release();
250}
251
252IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
253                       UpdateNonProgressNotificationWhenCenterVisible) {
254#if defined(OS_WIN) && defined(USE_ASH)
255  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
256  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
257    return;
258#endif
259
260  TestAddObserver observer(message_center());
261
262  TestDelegate* delegate;
263
264  // Add a non-progress notification and update it while the message center
265  // is visible.
266  Notification notification = CreateTestNotification("n", &delegate);
267  manager()->Add(notification, profile());
268  message_center()->ClickOnNotification("n");
269  message_center()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
270  observer.reset_logs();
271  notification.set_title(base::ASCIIToUTF16("title2"));
272  manager()->Update(notification, profile());
273
274  // Expect that the notification update is not done.
275  EXPECT_EQ("", observer.log("n"));
276
277  message_center()->SetVisibility(message_center::VISIBILITY_TRANSIENT);
278  EXPECT_EQ("update-n", observer.log("n"));
279
280  delegate->Release();
281}
282
283IN_PROC_BROWSER_TEST_F(
284    MessageCenterNotificationsTest,
285    UpdateNonProgressToProgressNotificationWhenCenterVisible) {
286#if defined(OS_WIN) && defined(USE_ASH)
287  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
288  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
289    return;
290#endif
291
292  TestAddObserver observer(message_center());
293
294  TestDelegate* delegate;
295
296  // Add a non-progress notification and change the type to progress while the
297  // message center is visible.
298  Notification notification = CreateTestNotification("n", &delegate);
299  manager()->Add(notification, profile());
300  message_center()->ClickOnNotification("n");
301  message_center()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
302  observer.reset_logs();
303  notification.set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
304  manager()->Update(notification, profile());
305
306  // Expect that the notification update is not done.
307  EXPECT_EQ("", observer.log("n"));
308
309  message_center()->SetVisibility(message_center::VISIBILITY_TRANSIENT);
310  EXPECT_EQ("update-n", observer.log("n"));
311
312  delegate->Release();
313}
314
315IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest,
316                       UpdateProgressNotificationWhenCenterVisible) {
317#if defined(OS_WIN) && defined(USE_ASH)
318  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
319  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
320    return;
321#endif
322
323  TestAddObserver observer(message_center());
324
325  TestDelegate* delegate;
326
327  // Add a progress notification and update it while the message center
328  // is visible.
329  Notification notification = CreateTestNotification("n", &delegate);
330  notification.set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
331  manager()->Add(notification, profile());
332  message_center()->ClickOnNotification("n");
333  message_center()->SetVisibility(message_center::VISIBILITY_MESSAGE_CENTER);
334  observer.reset_logs();
335  notification.set_progress(50);
336  manager()->Update(notification, profile());
337
338  // Expect that the progress notification update is performed.
339  EXPECT_EQ("update-n", observer.log("n"));
340
341  delegate->Release();
342}
343
344#endif  // !defined(OS_MACOSX)
345