1 // Copyright (c) 2012 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 "chrome/browser/chrome_notification_types.h" 7 #include "chrome/browser/extensions/extension_host.h" 8 #include "chrome/browser/extensions/extension_install_ui.h" 9 #include "chrome/browser/extensions/extension_service.h" 10 #include "chrome/browser/extensions/extension_system.h" 11 #include "chrome/browser/extensions/startup_helper.h" 12 #include "chrome/browser/extensions/webstore_installer_test.h" 13 #include "chrome/browser/infobars/infobar_service.h" 14 #include "chrome/browser/managed_mode/managed_user_service.h" 15 #include "chrome/browser/managed_mode/managed_user_service_factory.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/tabs/tab_strip_model.h" 19 #include "chrome/common/chrome_switches.h" 20 #include "chrome/common/pref_names.h" 21 #include "chrome/test/base/in_process_browser_test.h" 22 #include "chrome/test/base/test_switches.h" 23 #include "chrome/test/base/ui_test_utils.h" 24 #include "content/public/browser/notification_registrar.h" 25 #include "content/public/browser/notification_service.h" 26 #include "content/public/browser/notification_types.h" 27 #include "content/public/browser/web_contents.h" 28 #include "content/public/test/browser_test_utils.h" 29 #include "extensions/common/extension_builder.h" 30 #include "extensions/common/value_builder.h" 31 #include "net/dns/mock_host_resolver.h" 32 #include "url/gurl.h" 33 34 using content::WebContents; 35 using extensions::DictionaryBuilder; 36 using extensions::Extension; 37 using extensions::ExtensionBuilder; 38 using extensions::ListBuilder; 39 40 const char kWebstoreDomain[] = "cws.com"; 41 const char kAppDomain[] = "app.com"; 42 const char kNonAppDomain[] = "nonapp.com"; 43 const char kTestExtensionId[] = "ecglahbcnmdpdciemllbhojghbkagdje"; 44 const char kTestDataPath[] = "extensions/api_test/webstore_inline_install"; 45 const char kCrxFilename[] = "extension.crx"; 46 47 class WebstoreStartupInstallerTest : public WebstoreInstallerTest { 48 public: 49 WebstoreStartupInstallerTest() 50 : WebstoreInstallerTest( 51 kWebstoreDomain, 52 kTestDataPath, 53 kCrxFilename, 54 kAppDomain, 55 kNonAppDomain) {} 56 }; 57 58 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, Install) { 59 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 60 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 61 62 ui_test_utils::NavigateToURL( 63 browser(), GenerateTestServerUrl(kAppDomain, "install.html")); 64 65 RunTest("runTest"); 66 67 const extensions::Extension* extension = browser()->profile()-> 68 GetExtensionService()->GetExtensionById(kTestExtensionId, false); 69 EXPECT_TRUE(extension); 70 } 71 72 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, 73 InstallNotAllowedFromNonVerifiedDomains) { 74 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 75 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 76 ui_test_utils::NavigateToURL( 77 browser(), 78 GenerateTestServerUrl(kNonAppDomain, "install_non_verified_domain.html")); 79 80 RunTest("runTest1"); 81 RunTest("runTest2"); 82 } 83 84 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, FindLink) { 85 ui_test_utils::NavigateToURL( 86 browser(), GenerateTestServerUrl(kAppDomain, "find_link.html")); 87 88 RunTest("runTest"); 89 } 90 91 // Flakes on all platforms: http://crbug.com/95713, http://crbug.com/229947 92 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, 93 DISABLED_ArgumentValidation) { 94 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 95 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 96 97 // Each of these tests has to run separately, since one page/tab can 98 // only have one in-progress install request. These tests don't all pass 99 // callbacks to install, so they have no way to wait for the installation 100 // to complete before starting the next test. 101 bool is_finished = false; 102 for (int i = 0; !is_finished; ++i) { 103 ui_test_utils::NavigateToURL( 104 browser(), 105 GenerateTestServerUrl(kAppDomain, "argument_validation.html")); 106 is_finished = !RunIndexedTest("runTest", i); 107 } 108 } 109 110 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, MultipleInstallCalls) { 111 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 112 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 113 114 ui_test_utils::NavigateToURL( 115 browser(), 116 GenerateTestServerUrl(kAppDomain, "multiple_install_calls.html")); 117 RunTest("runTest"); 118 } 119 120 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallNotSupported) { 121 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 122 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 123 ui_test_utils::NavigateToURL( 124 browser(), 125 GenerateTestServerUrl(kAppDomain, "install_not_supported.html")); 126 127 ui_test_utils::WindowedTabAddedNotificationObserver observer( 128 content::NotificationService::AllSources()); 129 RunTest("runTest"); 130 observer.Wait(); 131 132 // The inline install should fail, and a store-provided URL should be opened 133 // in a new tab. 134 WebContents* web_contents = 135 browser()->tab_strip_model()->GetActiveWebContents(); 136 EXPECT_EQ(GURL("http://cws.com/show-me-the-money"), web_contents->GetURL()); 137 } 138 139 // Regression test for http://crbug.com/144991. 140 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallFromHostedApp) { 141 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 142 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 143 144 const GURL kInstallUrl = GenerateTestServerUrl(kAppDomain, "install.html"); 145 146 // We're forced to construct a hosted app dynamically because we need the 147 // app to run on a declared URL, but we don't know the port ahead of time. 148 scoped_refptr<const Extension> hosted_app = ExtensionBuilder() 149 .SetManifest(DictionaryBuilder() 150 .Set("name", "hosted app") 151 .Set("version", "1") 152 .Set("app", DictionaryBuilder() 153 .Set("urls", ListBuilder().Append(kInstallUrl.spec())) 154 .Set("launch", DictionaryBuilder() 155 .Set("web_url", kInstallUrl.spec()))) 156 .Set("manifest_version", 2)) 157 .Build(); 158 ASSERT_TRUE(hosted_app.get()); 159 160 ExtensionService* extension_service = 161 extensions::ExtensionSystem::Get(browser()->profile())-> 162 extension_service(); 163 164 extension_service->AddExtension(hosted_app.get()); 165 EXPECT_TRUE(extension_service->extensions()->Contains(hosted_app->id())); 166 167 ui_test_utils::NavigateToURL(browser(), kInstallUrl); 168 169 EXPECT_FALSE(extension_service->extensions()->Contains(kTestExtensionId)); 170 RunTest("runTest"); 171 EXPECT_TRUE(extension_service->extensions()->Contains(kTestExtensionId)); 172 } 173 174 class WebstoreStartupInstallerManagedUsersTest 175 : public WebstoreStartupInstallerTest { 176 public: 177 // InProcessBrowserTest overrides: 178 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 179 WebstoreStartupInstallerTest::SetUpCommandLine(command_line); 180 command_line->AppendSwitchASCII(switches::kManagedUserId, "asdf"); 181 } 182 }; 183 184 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerManagedUsersTest, 185 InstallProhibited) { 186 #if defined(OS_WIN) && defined(USE_ASH) 187 // Disable this test in Metro+Ash for now (http://crbug.com/262796). 188 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) 189 return; 190 #endif 191 192 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 193 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 194 195 ui_test_utils::NavigateToURL( 196 browser(), GenerateTestServerUrl(kAppDomain, "install_prohibited.html")); 197 198 RunTest("runTest"); 199 200 // No error infobar should show up. 201 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); 202 InfoBarService* info_bar_service = InfoBarService::FromWebContents(contents); 203 EXPECT_EQ(info_bar_service->infobar_count(), 0u); 204 } 205 206 // The unpack failure test needs to use a different install .crx, which is 207 // specified via a command-line flag, so it needs its own test subclass. 208 class WebstoreStartupInstallUnpackFailureTest 209 : public WebstoreStartupInstallerTest { 210 public: 211 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 212 WebstoreStartupInstallerTest::SetUpCommandLine(command_line); 213 214 GURL crx_url = GenerateTestServerUrl( 215 kWebstoreDomain, "malformed_extension.crx"); 216 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 217 switches::kAppsGalleryUpdateURL, crx_url.spec()); 218 } 219 220 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 221 WebstoreStartupInstallerTest::SetUpInProcessBrowserTestFixture(); 222 ExtensionInstallUI::set_disable_failure_ui_for_tests(); 223 } 224 }; 225 226 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallUnpackFailureTest, 227 WebstoreStartupInstallUnpackFailureTest) { 228 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 229 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 230 231 ui_test_utils::NavigateToURL(browser(), 232 GenerateTestServerUrl(kAppDomain, "install_unpack_failure.html")); 233 234 RunTest("runTest"); 235 } 236 237 class CommandLineWebstoreInstall : public WebstoreStartupInstallerTest, 238 public content::NotificationObserver { 239 public: 240 CommandLineWebstoreInstall() : saw_install_(false), browser_open_count_(0) {} 241 virtual ~CommandLineWebstoreInstall() {} 242 243 virtual void SetUpOnMainThread() OVERRIDE { 244 WebstoreStartupInstallerTest::SetUpOnMainThread(); 245 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, 246 content::NotificationService::AllSources()); 247 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, 248 content::NotificationService::AllSources()); 249 } 250 251 bool saw_install() { return saw_install_; } 252 253 int browser_open_count() { return browser_open_count_; } 254 255 // NotificationObserver interface. 256 virtual void Observe(int type, 257 const content::NotificationSource& source, 258 const content::NotificationDetails& details) OVERRIDE { 259 if (type == chrome::NOTIFICATION_EXTENSION_INSTALLED) { 260 const Extension* extension = 261 content::Details<const extensions::InstalledExtensionInfo>(details)-> 262 extension; 263 ASSERT_TRUE(extension != NULL); 264 EXPECT_EQ(extension->id(), kTestExtensionId); 265 saw_install_ = true; 266 } else if (type == chrome::NOTIFICATION_BROWSER_OPENED) { 267 browser_open_count_++; 268 } else { 269 ASSERT_TRUE(false) << "Unexpected notification type : " << type; 270 } 271 } 272 273 content::NotificationRegistrar registrar_; 274 275 // Have we seen an installation notification for kTestExtensionId ? 276 bool saw_install_; 277 278 // How many NOTIFICATION_BROWSER_OPENED notifications have we seen? 279 int browser_open_count_; 280 }; 281 282 IN_PROC_BROWSER_TEST_F(CommandLineWebstoreInstall, Accept) { 283 CommandLine* command_line = CommandLine::ForCurrentProcess(); 284 command_line->AppendSwitchASCII( 285 switches::kInstallFromWebstore, kTestExtensionId); 286 command_line->AppendSwitchASCII( 287 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 288 extensions::StartupHelper helper; 289 EXPECT_TRUE(helper.InstallFromWebstore(*command_line, browser()->profile())); 290 EXPECT_TRUE(saw_install()); 291 EXPECT_EQ(0, browser_open_count()); 292 } 293 294 IN_PROC_BROWSER_TEST_F(CommandLineWebstoreInstall, Cancel) { 295 CommandLine* command_line = CommandLine::ForCurrentProcess(); 296 command_line->AppendSwitchASCII( 297 switches::kInstallFromWebstore, kTestExtensionId); 298 command_line->AppendSwitchASCII( 299 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 300 extensions::StartupHelper helper; 301 EXPECT_FALSE(helper.InstallFromWebstore(*command_line, browser()->profile())); 302 EXPECT_FALSE(saw_install()); 303 EXPECT_EQ(0, browser_open_count()); 304 } 305 306 IN_PROC_BROWSER_TEST_F(CommandLineWebstoreInstall, LimitedAccept) { 307 extensions::StartupHelper helper; 308 309 // Small test of "WebStoreIdFromLimitedInstallCmdLine" which made more 310 // sense together with the rest of the test for "LimitedInstallFromWebstore". 311 CommandLine command_line_test1(CommandLine::NO_PROGRAM); 312 command_line_test1.AppendSwitchASCII(switches::kLimitedInstallFromWebstore, 313 "1"); 314 EXPECT_EQ("nckgahadagoaajjgafhacjanaoiihapd", 315 helper.WebStoreIdFromLimitedInstallCmdLine(command_line_test1)); 316 317 CommandLine command_line_test2(CommandLine::NO_PROGRAM); 318 command_line_test1.AppendSwitchASCII(switches::kLimitedInstallFromWebstore, 319 "2"); 320 EXPECT_EQ(kTestExtensionId, 321 helper.WebStoreIdFromLimitedInstallCmdLine(command_line_test1)); 322 323 // Now, on to the real test for LimitedInstallFromWebstore. 324 CommandLine* command_line = CommandLine::ForCurrentProcess(); 325 command_line->AppendSwitchASCII( 326 switches::kLimitedInstallFromWebstore, "2"); 327 helper.LimitedInstallFromWebstore(*command_line, browser()->profile(), 328 base::MessageLoop::QuitWhenIdleClosure()); 329 base::MessageLoop::current()->Run(); 330 331 EXPECT_TRUE(saw_install()); 332 EXPECT_EQ(0, browser_open_count()); 333 } 334