app_list_controller_browsertest.cc revision f2477e01787aa58f445919b809d89e252beef54f
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 "base/command_line.h"
6#include "base/file_util.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/message_loop/message_loop.h"
9#include "base/path_service.h"
10#include "base/prefs/pref_service.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/extensions/extension_browsertest.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/app_list_service.h"
18#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
19#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
20#include "chrome/browser/ui/browser.h"
21#include "chrome/browser/ui/browser_finder.h"
22#include "chrome/browser/ui/host_desktop.h"
23#include "chrome/common/chrome_paths.h"
24#include "chrome/common/chrome_switches.h"
25#include "chrome/common/pref_names.h"
26#include "chrome/test/base/in_process_browser_test.h"
27#include "chrome/test/base/ui_test_utils.h"
28#include "ui/app_list/app_list_model.h"
29#include "ui/app_list/search_box_model.h"
30#include "ui/app_list/search_result.h"
31#include "ui/app_list/search_result_observer.h"
32#include "ui/base/models/list_model_observer.h"
33
34namespace {
35
36app_list::AppListModel* GetAppListModel(AppListService* service) {
37  return app_list::AppListSyncableServiceFactory::GetForProfile(
38      service->GetCurrentAppListProfile())->model();
39}
40
41AppListService* GetAppListService() {
42  // TODO(tapted): Consider testing ash explicitly on the win-ash trybot.
43  return AppListService::Get(chrome::GetActiveDesktop());
44}
45
46}  // namespace
47
48// Browser Test for AppListController that runs on all platforms supporting
49// app_list.
50class AppListControllerBrowserTest : public InProcessBrowserTest {
51 public:
52  AppListControllerBrowserTest()
53    : profile2_(NULL) {}
54
55  void InitSecondProfile() {
56    ProfileManager* profile_manager = g_browser_process->profile_manager();
57    base::FilePath temp_profile_dir =
58        profile_manager->user_data_dir().AppendASCII("Profile 1");
59    profile_manager->CreateProfileAsync(
60        temp_profile_dir,
61        base::Bind(&AppListControllerBrowserTest::OnProfileCreated,
62                   this),
63        string16(), string16(), std::string());
64    content::RunMessageLoop();  // Will stop in OnProfileCreated().
65  }
66
67  void OnProfileCreated(Profile* profile, Profile::CreateStatus status) {
68    if (status == Profile::CREATE_STATUS_INITIALIZED) {
69      profile2_ = profile;
70      base::MessageLoop::current()->Quit();
71    }
72  }
73
74 protected:
75  Profile* profile2_;
76
77 private:
78  DISALLOW_COPY_AND_ASSIGN(AppListControllerBrowserTest);
79};
80
81// TODO(mgiuca): Enable on Linux when supported.
82#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
83#define MAYBE_CreateNewWindow DISABLED_CreateNewWindow
84#else
85#define MAYBE_CreateNewWindow CreateNewWindow
86#endif
87
88// Test the CreateNewWindow function of the controller delegate.
89IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest, MAYBE_CreateNewWindow) {
90  const chrome::HostDesktopType desktop = chrome::GetActiveDesktop();
91  AppListService* service = GetAppListService();
92  AppListControllerDelegate* controller(service->GetControllerDelegate());
93  ASSERT_TRUE(controller);
94
95  EXPECT_EQ(1U, chrome::GetBrowserCount(browser()->profile(), desktop));
96  EXPECT_EQ(0U, chrome::GetBrowserCount(
97      browser()->profile()->GetOffTheRecordProfile(), desktop));
98
99  controller->CreateNewWindow(browser()->profile(), false);
100  EXPECT_EQ(2U, chrome::GetBrowserCount(browser()->profile(), desktop));
101
102  controller->CreateNewWindow(browser()->profile(), true);
103  EXPECT_EQ(1U, chrome::GetBrowserCount(
104      browser()->profile()->GetOffTheRecordProfile(), desktop));
105}
106
107// TODO(mgiuca): Enable on Linux/ChromeOS when supported.
108#if defined(OS_LINUX)
109#define MAYBE_ShowAndDismiss DISABLED_ShowAndDismiss
110#define MAYBE_SwitchAppListProfiles DISABLED_SwitchAppListProfiles
111#define MAYBE_SwitchAppListProfilesDuringSearch \
112  DISABLED_SwitchAppListProfilesDuringSearch
113#else
114#define MAYBE_ShowAndDismiss ShowAndDismiss
115#define MAYBE_SwitchAppListProfiles SwitchAppListProfiles
116#define MAYBE_SwitchAppListProfilesDuringSearch \
117  SwitchAppListProfilesDuringSearch
118#endif
119
120// Show the app list, then dismiss it.
121IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest, MAYBE_ShowAndDismiss) {
122  AppListService* service = GetAppListService();
123  ASSERT_FALSE(service->IsAppListVisible());
124  service->ShowForProfile(browser()->profile());
125  ASSERT_TRUE(service->IsAppListVisible());
126  service->DismissAppList();
127  ASSERT_FALSE(service->IsAppListVisible());
128}
129
130IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest,
131                       MAYBE_SwitchAppListProfiles) {
132  InitSecondProfile();
133
134  AppListService* service = GetAppListService();
135  ASSERT_TRUE(service);
136
137  AppListControllerDelegate* controller(service->GetControllerDelegate());
138  ASSERT_TRUE(controller);
139
140  // Open the app list with the browser's profile.
141  ASSERT_FALSE(service->IsAppListVisible());
142  controller->ShowForProfileByPath(browser()->profile()->GetPath());
143  app_list::AppListModel* model = GetAppListModel(service);
144  ASSERT_TRUE(model);
145  model->SetSignedIn(true);
146  base::RunLoop().RunUntilIdle();
147
148  ASSERT_TRUE(service->IsAppListVisible());
149  ASSERT_EQ(browser()->profile(), service->GetCurrentAppListProfile());
150
151  // Open the app list with the second profile.
152  controller->ShowForProfileByPath(profile2_->GetPath());
153  model = GetAppListModel(service);
154  ASSERT_TRUE(model);
155  model->SetSignedIn(true);
156  base::RunLoop().RunUntilIdle();
157
158  ASSERT_TRUE(service->IsAppListVisible());
159  ASSERT_EQ(profile2_, service->GetCurrentAppListProfile());
160
161  controller->DismissView();
162}
163
164IN_PROC_BROWSER_TEST_F(AppListControllerBrowserTest,
165                       MAYBE_SwitchAppListProfilesDuringSearch) {
166  InitSecondProfile();
167
168  AppListService* service = GetAppListService();
169  ASSERT_TRUE(service);
170
171  AppListControllerDelegate* controller(service->GetControllerDelegate());
172  ASSERT_TRUE(controller);
173
174  // Set a search with original profile.
175  controller->ShowForProfileByPath(browser()->profile()->GetPath());
176  app_list::AppListModel* model = GetAppListModel(service);
177  ASSERT_TRUE(model);
178  model->SetSignedIn(true);
179  model->search_box()->SetText(ASCIIToUTF16("minimal"));
180  base::RunLoop().RunUntilIdle();
181
182  // Switch to the second profile.
183  controller->ShowForProfileByPath(profile2_->GetPath());
184  model = GetAppListModel(service);
185  ASSERT_TRUE(model);
186  model->SetSignedIn(true);
187  base::RunLoop().RunUntilIdle();
188
189  // Ensure the search box is empty.
190  ASSERT_TRUE(model->search_box()->text().empty());
191  ASSERT_EQ(profile2_, service->GetCurrentAppListProfile());
192
193  controller->DismissView();
194  ASSERT_FALSE(service->IsAppListVisible());
195}
196
197class ShowAppListBrowserTest : public InProcessBrowserTest {
198 public:
199  ShowAppListBrowserTest() {}
200
201  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
202    command_line->AppendSwitch(switches::kShowAppList);
203  }
204
205 private:
206  DISALLOW_COPY_AND_ASSIGN(ShowAppListBrowserTest);
207};
208
209// See http://crbug.com/315677
210#if defined(OS_WIN)
211#define MAYBE_ShowAppListFlag DISABLED_ShowAppListFlag
212#else
213#define MAYBE_ShowAppListFlag ShowAppListFlag
214#endif
215
216IN_PROC_BROWSER_TEST_F(ShowAppListBrowserTest, MAYBE_ShowAppListFlag) {
217  AppListService* service = GetAppListService();
218  // The app list should already be shown because we passed
219  // switches::kShowAppList.
220  ASSERT_TRUE(service->IsAppListVisible());
221
222  // Create a browser to prevent shutdown when we dismiss the app list.  We
223  // need to do this because switches::kShowAppList suppresses the creation of
224  // any browsers.
225  CreateBrowser(service->GetCurrentAppListProfile());
226  service->DismissAppList();
227}
228
229// Browser Test for AppListController that observes search result changes.
230class AppListControllerSearchResultsBrowserTest
231    : public ExtensionBrowserTest,
232      public app_list::SearchResultObserver,
233      public ui::ListModelObserver {
234 public:
235  AppListControllerSearchResultsBrowserTest()
236      : observed_result_(NULL),
237        item_uninstall_count_(0),
238        observed_results_list_(NULL) {}
239
240  void WatchResultsLookingForItem(
241      app_list::AppListModel::SearchResults* search_results,
242      const std::string& extension_name) {
243    EXPECT_FALSE(observed_results_list_);
244    observed_results_list_ = search_results;
245    observed_results_list_->AddObserver(this);
246    item_to_observe_ = ASCIIToUTF16(extension_name);
247  }
248
249  void StopWatchingResults() {
250    EXPECT_TRUE(observed_results_list_);
251    observed_results_list_->RemoveObserver(this);
252  }
253
254 protected:
255  void AttemptToLocateItem() {
256    if (observed_result_) {
257      observed_result_->RemoveObserver(this);
258      observed_result_ = NULL;
259    }
260
261    for (size_t i = 0; i < observed_results_list_->item_count(); ++i) {
262      if (observed_results_list_->GetItemAt(i)->title() != item_to_observe_)
263        continue;
264
265      // Ensure there is at most one.
266      EXPECT_FALSE(observed_result_);
267      observed_result_ = observed_results_list_->GetItemAt(i);
268    }
269
270    if (observed_result_)
271      observed_result_->AddObserver(this);
272  }
273
274  // Overridden from SearchResultObserver:
275  virtual void OnIconChanged() OVERRIDE {}
276  virtual void OnActionsChanged() OVERRIDE {}
277  virtual void OnIsInstallingChanged() OVERRIDE {}
278  virtual void OnPercentDownloadedChanged() OVERRIDE {}
279  virtual void OnItemInstalled() OVERRIDE {}
280  virtual void OnItemUninstalled() OVERRIDE {
281    ++item_uninstall_count_;
282    EXPECT_TRUE(observed_result_);
283  }
284
285  // Overridden from ui::ListModelObserver:
286  virtual void ListItemsAdded(size_t start, size_t count) OVERRIDE {
287    AttemptToLocateItem();
288  }
289  virtual void ListItemsRemoved(size_t start, size_t count) OVERRIDE {
290    AttemptToLocateItem();
291  }
292  virtual void ListItemMoved(size_t index, size_t target_index) OVERRIDE {}
293  virtual void ListItemsChanged(size_t start, size_t count) OVERRIDE {}
294
295  app_list::SearchResult* observed_result_;
296  int item_uninstall_count_;
297
298 private:
299  base::string16 item_to_observe_;
300  app_list::AppListModel::SearchResults* observed_results_list_;
301
302  DISALLOW_COPY_AND_ASSIGN(AppListControllerSearchResultsBrowserTest);
303};
304
305// TODO(mgiuca): Enable on Linux when supported.
306#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
307#define MAYBE_UninstallSearchResult DISABLED_UninstallSearchResult
308#else
309#define MAYBE_UninstallSearchResult UninstallSearchResult
310#endif
311
312// Test showing search results, and uninstalling one of them while displayed.
313IN_PROC_BROWSER_TEST_F(AppListControllerSearchResultsBrowserTest,
314                       UninstallSearchResult) {
315  base::FilePath test_extension_path;
316  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_extension_path));
317  test_extension_path = test_extension_path.AppendASCII("extensions")
318      .AppendASCII("platform_apps")
319      .AppendASCII("minimal");
320  const extensions::Extension* extension =
321      InstallExtension(test_extension_path,
322                       1 /* expected_change: new install */);
323  ASSERT_TRUE(extension);
324
325  AppListService* service = GetAppListService();
326  ASSERT_TRUE(service);
327  service->ShowForProfile(browser()->profile());
328
329  app_list::AppListModel* model = GetAppListModel(service);
330  ASSERT_TRUE(model);
331  model->SetSignedIn(true);
332  WatchResultsLookingForItem(model->results(), extension->name());
333
334  // Ensure a search finds the extension.
335  EXPECT_FALSE(observed_result_);
336  model->search_box()->SetText(ASCIIToUTF16("minimal"));
337  EXPECT_TRUE(observed_result_);
338
339  // Ensure the UI is updated. This is via PostTask in views.
340  base::RunLoop().RunUntilIdle();
341
342  // Now uninstall and ensure this browser test observes it.
343  EXPECT_EQ(0, item_uninstall_count_);
344  UninstallExtension(extension->id());
345  EXPECT_EQ(1, item_uninstall_count_);
346
347  // Results should not be immediately refreshed. When they are, the item should
348  // be removed from the model.
349  EXPECT_TRUE(observed_result_);
350  base::RunLoop().RunUntilIdle();
351  EXPECT_FALSE(observed_result_);
352  StopWatchingResults();
353  service->DismissAppList();
354}
355