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 "chrome/browser/ui/cocoa/apps/quit_with_apps_controller_mac.h"
6
7#include "base/command_line.h"
8#include "base/run_loop.h"
9#include "chrome/browser/apps/app_browsertest_util.h"
10#include "chrome/browser/apps/app_window_registry_util.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/chrome_browser_application_mac.h"
13#include "chrome/browser/extensions/extension_service.h"
14#include "chrome/browser/lifetime/application_lifetime.h"
15#include "chrome/browser/notifications/message_center_notification_manager.h"
16#include "chrome/browser/notifications/notification_ui_manager.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/ui/browser_iterator.h"
19#include "chrome/browser/ui/browser_window.h"
20#include "chrome/common/chrome_switches.h"
21#include "content/public/browser/notification_service.h"
22#include "content/public/test/test_utils.h"
23#include "extensions/common/extension.h"
24#include "extensions/test/extension_test_message_listener.h"
25#include "ui/message_center/message_center.h"
26
27namespace {
28
29class QuitWithAppsControllerInteractiveTest
30    : public extensions::PlatformAppBrowserTest {
31 protected:
32  QuitWithAppsControllerInteractiveTest() : app_(NULL) {}
33
34  virtual ~QuitWithAppsControllerInteractiveTest() {}
35
36  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
37    PlatformAppBrowserTest::SetUpCommandLine(command_line);
38    command_line->AppendSwitch(switches::kAppsKeepChromeAliveInTests);
39  }
40
41  const extensions::Extension* app_;
42
43 private:
44  DISALLOW_COPY_AND_ASSIGN(QuitWithAppsControllerInteractiveTest);
45};
46
47}  // namespace
48
49// Test that quitting while apps are open shows a notification instead.
50IN_PROC_BROWSER_TEST_F(QuitWithAppsControllerInteractiveTest, QuitBehavior) {
51  scoped_refptr<QuitWithAppsController> controller =
52      new QuitWithAppsController();
53  const Notification* notification;
54  message_center::MessageCenter* message_center =
55      message_center::MessageCenter::Get();
56
57  // With no app windows open, ShouldQuit returns true.
58  EXPECT_TRUE(controller->ShouldQuit());
59  notification = g_browser_process->notification_ui_manager()->FindById(
60      QuitWithAppsController::kQuitWithAppsNotificationID);
61  EXPECT_EQ(NULL, notification);
62
63  // Open an app window.
64  ExtensionTestMessageListener listener("Launched", false);
65  app_ = InstallAndLaunchPlatformApp("minimal_id");
66  ASSERT_TRUE(listener.WaitUntilSatisfied());
67
68  // One browser and one app window at this point.
69  EXPECT_FALSE(chrome::BrowserIterator().done());
70  EXPECT_TRUE(AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0));
71
72  // On the first quit, show notification.
73  EXPECT_FALSE(controller->ShouldQuit());
74  EXPECT_TRUE(AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0));
75  notification = g_browser_process->notification_ui_manager()->FindById(
76      QuitWithAppsController::kQuitWithAppsNotificationID);
77  ASSERT_TRUE(notification);
78
79  // If notification was dismissed by click, show again on next quit.
80  notification->delegate()->Click();
81  message_center->RemoveAllNotifications(false);
82  EXPECT_FALSE(controller->ShouldQuit());
83  EXPECT_TRUE(AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0));
84  notification = g_browser_process->notification_ui_manager()->FindById(
85      QuitWithAppsController::kQuitWithAppsNotificationID);
86  ASSERT_TRUE(notification);
87
88  EXPECT_FALSE(chrome::BrowserIterator().done());
89  EXPECT_TRUE(AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0));
90
91  // If notification is closed by user, don't show it next time.
92  notification->delegate()->Close(true);
93  message_center->RemoveAllNotifications(false);
94  EXPECT_FALSE(controller->ShouldQuit());
95  EXPECT_TRUE(AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0));
96  notification = g_browser_process->notification_ui_manager()->FindById(
97      QuitWithAppsController::kQuitWithAppsNotificationID);
98  EXPECT_EQ(NULL, notification);
99
100  EXPECT_FALSE(chrome::BrowserIterator().done());
101  EXPECT_TRUE(AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0));
102
103  // Quitting should not quit but close all browsers
104  content::WindowedNotificationObserver observer(
105      chrome::NOTIFICATION_BROWSER_CLOSED,
106      content::NotificationService::AllSources());
107  chrome_browser_application_mac::Terminate();
108  observer.Wait();
109
110  EXPECT_TRUE(chrome::BrowserIterator().done());
111  EXPECT_TRUE(AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0));
112
113  // Trying to quit while there are no browsers always shows notification.
114  EXPECT_FALSE(controller->ShouldQuit());
115  notification = g_browser_process->notification_ui_manager()->FindById(
116      QuitWithAppsController::kQuitWithAppsNotificationID);
117  ASSERT_TRUE(notification);
118
119  // Clicking "Quit All Apps." button closes all app windows. With no browsers
120  // open, this should also quit Chrome.
121  content::WindowedNotificationObserver quit_observer(
122      chrome::NOTIFICATION_APP_TERMINATING,
123      content::NotificationService::AllSources());
124  notification->delegate()->ButtonClick(0);
125  message_center->RemoveAllNotifications(false);
126  EXPECT_FALSE(AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0));
127  quit_observer.Wait();
128}
129