1// Copyright 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 "chrome/browser/ui/app_list/app_list_service.h"
6
7#include "base/command_line.h"
8#include "base/json/json_file_value_serializer.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/message_loop/message_loop.h"
11#include "base/path_service.h"
12#include "base/strings/utf_string_conversions.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/profiles/profile_manager.h"
16#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
17#include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h"
18#include "chrome/browser/ui/browser.h"
19#include "chrome/browser/ui/host_desktop.h"
20#include "chrome/browser/ui/startup/startup_browser_creator.h"
21#include "chrome/common/chrome_constants.h"
22#include "chrome/common/chrome_paths.h"
23#include "chrome/common/chrome_switches.h"
24#include "chrome/common/pref_names.h"
25#include "chrome/test/base/in_process_browser_test.h"
26#include "chrome/test/base/ui_test_utils.h"
27#include "ui/app_list/app_list_model.h"
28#include "ui/app_list/search_box_model.h"
29
30// Interactive UI Test for AppListService that runs on all platforms supporting
31// app_list. Interactive because the app list uses focus changes to dismiss
32// itself, which will cause tests that check the visibility to fail flakily.
33class AppListServiceInteractiveTest : public InProcessBrowserTest {
34 public:
35  AppListServiceInteractiveTest()
36    : profile2_(NULL) {}
37
38  void InitSecondProfile() { profile2_ = test::CreateSecondProfileAsync(); }
39
40 protected:
41  Profile* profile2_;
42
43 private:
44  DISALLOW_COPY_AND_ASSIGN(AppListServiceInteractiveTest);
45};
46
47// ChromeOS does not support ShowForProfile(), or profile switching within the
48// app list. Profile switching on CrOS goes through a different code path.
49#if defined(OS_CHROMEOS)
50#define MAYBE_ShowAndDismiss DISABLED_ShowAndDismiss
51#define MAYBE_SwitchAppListProfiles DISABLED_SwitchAppListProfiles
52#define MAYBE_SwitchAppListProfilesDuringSearch \
53    DISABLED_SwitchAppListProfilesDuringSearch
54#define MAYBE_ShowAppListNonDefaultProfile \
55    DISABLED_ShowAppListNonDefaultProfile
56#define MAYBE_DeleteShowingAppList DISABLED_DeleteShowingAppList
57#else
58#define MAYBE_ShowAndDismiss ShowAndDismiss
59#define MAYBE_SwitchAppListProfiles SwitchAppListProfiles
60#define MAYBE_SwitchAppListProfilesDuringSearch \
61    SwitchAppListProfilesDuringSearch
62#define MAYBE_ShowAppListNonDefaultProfile ShowAppListNonDefaultProfile
63#define MAYBE_DeleteShowingAppList DeleteShowingAppList
64#endif
65
66// Show the app list, then dismiss it.
67IN_PROC_BROWSER_TEST_F(AppListServiceInteractiveTest, MAYBE_ShowAndDismiss) {
68  AppListService* service = test::GetAppListService();
69  ASSERT_FALSE(service->IsAppListVisible());
70  service->ShowForProfile(browser()->profile());
71  ASSERT_TRUE(service->IsAppListVisible());
72  service->DismissAppList();
73  ASSERT_FALSE(service->IsAppListVisible());
74}
75
76// Switch profiles on the app list while it is showing.
77IN_PROC_BROWSER_TEST_F(AppListServiceInteractiveTest,
78                       MAYBE_SwitchAppListProfiles) {
79  InitSecondProfile();
80
81  AppListService* service = test::GetAppListService();
82  ASSERT_TRUE(service);
83
84  AppListControllerDelegate* controller(service->GetControllerDelegate());
85  ASSERT_TRUE(controller);
86
87  // Open the app list with the browser's profile.
88  ASSERT_FALSE(service->IsAppListVisible());
89  controller->ShowForProfileByPath(browser()->profile()->GetPath());
90  app_list::AppListModel* model = test::GetAppListModel(service);
91  ASSERT_TRUE(model);
92
93  base::RunLoop().RunUntilIdle();
94
95  ASSERT_TRUE(service->IsAppListVisible());
96  ASSERT_EQ(browser()->profile(), service->GetCurrentAppListProfile());
97
98  // Open the app list with the second profile.
99  controller->ShowForProfileByPath(profile2_->GetPath());
100  model = test::GetAppListModel(service);
101  ASSERT_TRUE(model);
102  base::RunLoop().RunUntilIdle();
103
104  ASSERT_TRUE(service->IsAppListVisible());
105  ASSERT_EQ(profile2_, service->GetCurrentAppListProfile());
106
107  controller->DismissView();
108}
109
110// Test switching app list profiles while search results are visibile.
111IN_PROC_BROWSER_TEST_F(AppListServiceInteractiveTest,
112                       MAYBE_SwitchAppListProfilesDuringSearch) {
113  InitSecondProfile();
114
115  AppListService* service = test::GetAppListService();
116  ASSERT_TRUE(service);
117
118  AppListControllerDelegate* controller(service->GetControllerDelegate());
119  ASSERT_TRUE(controller);
120
121  // Set a search with original profile.
122  controller->ShowForProfileByPath(browser()->profile()->GetPath());
123  app_list::AppListModel* model = test::GetAppListModel(service);
124  ASSERT_TRUE(model);
125
126  model->search_box()->SetText(base::ASCIIToUTF16("minimal"));
127  base::RunLoop().RunUntilIdle();
128
129  // Switch to the second profile.
130  controller->ShowForProfileByPath(profile2_->GetPath());
131  model = test::GetAppListModel(service);
132  ASSERT_TRUE(model);
133  base::RunLoop().RunUntilIdle();
134
135  // Ensure the search box is empty.
136  ASSERT_TRUE(model->search_box()->text().empty());
137  ASSERT_EQ(profile2_, service->GetCurrentAppListProfile());
138
139  controller->DismissView();
140  ASSERT_FALSE(service->IsAppListVisible());
141}
142
143// Interactive UI test that adds the --show-app-list command line switch.
144class ShowAppListInteractiveTest : public InProcessBrowserTest {
145 public:
146  ShowAppListInteractiveTest() {}
147
148  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
149    command_line->AppendSwitch(switches::kShowAppList);
150  }
151
152 private:
153  DISALLOW_COPY_AND_ASSIGN(ShowAppListInteractiveTest);
154};
155
156// Test showing the app list using the command line switch.
157#if defined(OS_CHROMEOS)
158// http://crbug.com/396499
159#define MAYBE_ShowAppListFlag DISABLED_ShowAppListFlag
160#else
161#define MAYBE_ShowAppListFlag ShowAppListFlag
162#endif
163IN_PROC_BROWSER_TEST_F(ShowAppListInteractiveTest, MAYBE_ShowAppListFlag) {
164  AppListService* service = test::GetAppListService();
165  // The app list should already be shown because we passed
166  // switches::kShowAppList.
167  EXPECT_TRUE(service->IsAppListVisible());
168
169  // Create a browser to prevent shutdown when we dismiss the app list.  We
170  // need to do this because switches::kShowAppList suppresses the creation of
171  // any browsers.
172  Profile* profile = service->GetCurrentAppListProfile();
173  CreateBrowser(profile);
174
175  service->DismissAppList();
176  EXPECT_FALSE(service->IsAppListVisible());
177
178  // With Chrome still running, test receiving a second --show-app-list request
179  // via the process singleton. ChromeOS has no process singleton so exclude it.
180#if !defined(OS_CHROMEOS)
181  CommandLine command_line(CommandLine::NO_PROGRAM);
182  command_line.AppendSwitch(switches::kShowAppList);
183  StartupBrowserCreator::ProcessCommandLineAlreadyRunning(
184      command_line, base::FilePath(), profile->GetPath());
185
186  EXPECT_TRUE(service->IsAppListVisible());
187  service->DismissAppList();
188  EXPECT_FALSE(service->IsAppListVisible());
189#endif
190}
191
192// Interactive UI test that creates a non-default profile and configures it for
193// the --show-app-list flag.
194class ShowAppListNonDefaultInteractiveTest : public ShowAppListInteractiveTest {
195 public:
196  ShowAppListNonDefaultInteractiveTest()
197      : second_profile_name_(FILE_PATH_LITERAL("Profile 1")) {
198  }
199
200  virtual bool SetUpUserDataDirectory() OVERRIDE {
201    // Create a temp dir for "Profile 1" and seed the user data dir with a Local
202    // State file configuring the app list to use it.
203    base::FilePath user_data_dir;
204    CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
205    base::FilePath profile_path = user_data_dir.Append(second_profile_name_);
206    CHECK(second_profile_temp_dir_.Set(profile_path));
207
208    base::FilePath local_pref_path =
209        user_data_dir.Append(chrome::kLocalStateFilename);
210    base::DictionaryValue dict;
211    dict.SetString(prefs::kAppListProfile,
212                   second_profile_name_.MaybeAsASCII());
213    CHECK(JSONFileValueSerializer(local_pref_path).Serialize(dict));
214
215    return InProcessBrowserTest::SetUpUserDataDirectory();
216  }
217
218 protected:
219  const base::FilePath second_profile_name_;
220  base::ScopedTempDir second_profile_temp_dir_;
221
222 private:
223  DISALLOW_COPY_AND_ASSIGN(ShowAppListNonDefaultInteractiveTest);
224};
225
226// Test showing the app list for a profile that doesn't match the browser
227// profile.
228IN_PROC_BROWSER_TEST_F(ShowAppListNonDefaultInteractiveTest,
229                       MAYBE_ShowAppListNonDefaultProfile) {
230  AppListService* service = test::GetAppListService();
231  EXPECT_TRUE(service->IsAppListVisible());
232  EXPECT_EQ(second_profile_name_.value(),
233            service->GetCurrentAppListProfile()->GetPath().BaseName().value());
234
235  // Check that the default profile hasn't been loaded.
236  ProfileManager* profile_manager = g_browser_process->profile_manager();
237  EXPECT_EQ(1u, profile_manager->GetNumberOfProfiles());
238
239  // Create a browser for the Default profile. This stops MaybeTeminate being
240  // called when the app list window is dismissed. Use the last used browser
241  // profile to verify that it is different and causes ProfileManager to load a
242  // new profile.
243  CreateBrowser(profile_manager->GetLastUsedProfile());
244  EXPECT_EQ(2u, profile_manager->GetNumberOfProfiles());
245
246  service->DismissAppList();
247}
248
249// Test showing the app list for a profile then deleting that profile while the
250// app list is visible.
251IN_PROC_BROWSER_TEST_F(ShowAppListNonDefaultInteractiveTest,
252                       MAYBE_DeleteShowingAppList) {
253  AppListService* service = test::GetAppListService();
254  EXPECT_TRUE(service->IsAppListVisible());
255  EXPECT_EQ(second_profile_name_.value(),
256            service->GetCurrentAppListProfile()->GetPath().BaseName().value());
257
258  ProfileManager* profile_manager = g_browser_process->profile_manager();
259
260  // Create a browser for the Default profile.
261  CreateBrowser(profile_manager->GetLastUsedProfile());
262
263  // Delete the profile being used by the app list.
264  profile_manager->ScheduleProfileForDeletion(
265      service->GetCurrentAppListProfile()->GetPath(),
266      ProfileManager::CreateCallback());
267
268  // App Launcher should get closed immediately and nothing should explode.
269  EXPECT_FALSE(service->IsAppListVisible());
270}
271