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