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