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_install_ui.h" 8 #include "chrome/browser/extensions/extension_service.h" 9 #include "chrome/browser/extensions/startup_helper.h" 10 #include "chrome/browser/extensions/webstore_installer_test.h" 11 #include "chrome/browser/infobars/infobar_service.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/ui/browser.h" 14 #include "chrome/browser/ui/tabs/tab_strip_model.h" 15 #include "chrome/common/chrome_switches.h" 16 #include "chrome/common/pref_names.h" 17 #include "chrome/test/base/in_process_browser_test.h" 18 #include "chrome/test/base/test_switches.h" 19 #include "chrome/test/base/ui_test_utils.h" 20 #include "content/public/browser/notification_registrar.h" 21 #include "content/public/browser/notification_service.h" 22 #include "content/public/browser/notification_types.h" 23 #include "content/public/browser/web_contents.h" 24 #include "content/public/test/browser_test_utils.h" 25 #include "extensions/browser/extension_host.h" 26 #include "extensions/browser/extension_system.h" 27 #include "extensions/common/extension_builder.h" 28 #include "extensions/common/value_builder.h" 29 #include "net/dns/mock_host_resolver.h" 30 #include "url/gurl.h" 31 32 using content::WebContents; 33 using extensions::DictionaryBuilder; 34 using extensions::Extension; 35 using extensions::ExtensionBuilder; 36 using extensions::ListBuilder; 37 38 const char kWebstoreDomain[] = "cws.com"; 39 const char kAppDomain[] = "app.com"; 40 const char kNonAppDomain[] = "nonapp.com"; 41 const char kTestExtensionId[] = "ecglahbcnmdpdciemllbhojghbkagdje"; 42 const char kTestDataPath[] = "extensions/api_test/webstore_inline_install"; 43 const char kCrxFilename[] = "extension.crx"; 44 45 class WebstoreStartupInstallerTest : public WebstoreInstallerTest { 46 public: 47 WebstoreStartupInstallerTest() 48 : WebstoreInstallerTest( 49 kWebstoreDomain, 50 kTestDataPath, 51 kCrxFilename, 52 kAppDomain, 53 kNonAppDomain) {} 54 }; 55 56 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, Install) { 57 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 58 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 59 60 ui_test_utils::NavigateToURL( 61 browser(), GenerateTestServerUrl(kAppDomain, "install.html")); 62 63 RunTest("runTest"); 64 65 const extensions::Extension* extension = browser()->profile()-> 66 GetExtensionService()->GetExtensionById(kTestExtensionId, false); 67 EXPECT_TRUE(extension); 68 } 69 70 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, 71 InstallNotAllowedFromNonVerifiedDomains) { 72 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 73 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 74 ui_test_utils::NavigateToURL( 75 browser(), 76 GenerateTestServerUrl(kNonAppDomain, "install_non_verified_domain.html")); 77 78 RunTest("runTest1"); 79 RunTest("runTest2"); 80 } 81 82 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, FindLink) { 83 ui_test_utils::NavigateToURL( 84 browser(), GenerateTestServerUrl(kAppDomain, "find_link.html")); 85 86 RunTest("runTest"); 87 } 88 89 // Flakes on all platforms: http://crbug.com/95713, http://crbug.com/229947 90 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, 91 DISABLED_ArgumentValidation) { 92 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 93 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 94 95 // Each of these tests has to run separately, since one page/tab can 96 // only have one in-progress install request. These tests don't all pass 97 // callbacks to install, so they have no way to wait for the installation 98 // to complete before starting the next test. 99 bool is_finished = false; 100 for (int i = 0; !is_finished; ++i) { 101 ui_test_utils::NavigateToURL( 102 browser(), 103 GenerateTestServerUrl(kAppDomain, "argument_validation.html")); 104 is_finished = !RunIndexedTest("runTest", i); 105 } 106 } 107 108 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, MultipleInstallCalls) { 109 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 110 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 111 112 ui_test_utils::NavigateToURL( 113 browser(), 114 GenerateTestServerUrl(kAppDomain, "multiple_install_calls.html")); 115 RunTest("runTest"); 116 } 117 118 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallNotSupported) { 119 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 120 switches::kAppsGalleryInstallAutoConfirmForTests, "cancel"); 121 ui_test_utils::NavigateToURL( 122 browser(), 123 GenerateTestServerUrl(kAppDomain, "install_not_supported.html")); 124 125 ui_test_utils::WindowedTabAddedNotificationObserver observer( 126 content::NotificationService::AllSources()); 127 RunTest("runTest"); 128 observer.Wait(); 129 130 // The inline install should fail, and a store-provided URL should be opened 131 // in a new tab. 132 WebContents* web_contents = 133 browser()->tab_strip_model()->GetActiveWebContents(); 134 EXPECT_EQ(GURL("http://cws.com/show-me-the-money"), web_contents->GetURL()); 135 } 136 137 // Regression test for http://crbug.com/144991. 138 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerTest, InstallFromHostedApp) { 139 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 140 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 141 142 const GURL kInstallUrl = GenerateTestServerUrl(kAppDomain, "install.html"); 143 144 // We're forced to construct a hosted app dynamically because we need the 145 // app to run on a declared URL, but we don't know the port ahead of time. 146 scoped_refptr<const Extension> hosted_app = ExtensionBuilder() 147 .SetManifest(DictionaryBuilder() 148 .Set("name", "hosted app") 149 .Set("version", "1") 150 .Set("app", DictionaryBuilder() 151 .Set("urls", ListBuilder().Append(kInstallUrl.spec())) 152 .Set("launch", DictionaryBuilder() 153 .Set("web_url", kInstallUrl.spec()))) 154 .Set("manifest_version", 2)) 155 .Build(); 156 ASSERT_TRUE(hosted_app.get()); 157 158 ExtensionService* extension_service = 159 extensions::ExtensionSystem::Get(browser()->profile())-> 160 extension_service(); 161 162 extension_service->AddExtension(hosted_app.get()); 163 EXPECT_TRUE(extension_service->extensions()->Contains(hosted_app->id())); 164 165 ui_test_utils::NavigateToURL(browser(), kInstallUrl); 166 167 EXPECT_FALSE(extension_service->extensions()->Contains(kTestExtensionId)); 168 RunTest("runTest"); 169 EXPECT_TRUE(extension_service->extensions()->Contains(kTestExtensionId)); 170 } 171 172 class WebstoreStartupInstallerManagedUsersTest 173 : public WebstoreStartupInstallerTest { 174 public: 175 // InProcessBrowserTest overrides: 176 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE { 177 WebstoreStartupInstallerTest::SetUpCommandLine(command_line); 178 command_line->AppendSwitchASCII(switches::kSupervisedUserId, "asdf"); 179 } 180 }; 181 182 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallerManagedUsersTest, 183 InstallProhibited) { 184 #if defined(OS_WIN) && defined(USE_ASH) 185 // Disable this test in Metro+Ash for now (http://crbug.com/262796). 186 if (base::CommandLine::ForCurrentProcess()->HasSwitch( 187 switches::kAshBrowserTests)) 188 return; 189 #endif 190 191 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 192 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 193 194 ui_test_utils::NavigateToURL( 195 browser(), GenerateTestServerUrl(kAppDomain, "install_prohibited.html")); 196 197 RunTest("runTest"); 198 199 // No error infobar should show up. 200 WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); 201 InfoBarService* infobar_service = InfoBarService::FromWebContents(contents); 202 EXPECT_EQ(0u, infobar_service->infobar_count()); 203 } 204 205 // The unpack failure test needs to use a different install .crx, which is 206 // specified via a command-line flag, so it needs its own test subclass. 207 class WebstoreStartupInstallUnpackFailureTest 208 : public WebstoreStartupInstallerTest { 209 public: 210 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE { 211 WebstoreStartupInstallerTest::SetUpCommandLine(command_line); 212 213 GURL crx_url = GenerateTestServerUrl( 214 kWebstoreDomain, "malformed_extension.crx"); 215 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 216 switches::kAppsGalleryUpdateURL, crx_url.spec()); 217 } 218 219 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 220 WebstoreStartupInstallerTest::SetUpInProcessBrowserTestFixture(); 221 ExtensionInstallUI::set_disable_failure_ui_for_tests(); 222 } 223 }; 224 225 IN_PROC_BROWSER_TEST_F(WebstoreStartupInstallUnpackFailureTest, 226 WebstoreStartupInstallUnpackFailureTest) { 227 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( 228 switches::kAppsGalleryInstallAutoConfirmForTests, "accept"); 229 230 ui_test_utils::NavigateToURL(browser(), 231 GenerateTestServerUrl(kAppDomain, "install_unpack_failure.html")); 232 233 RunTest("runTest"); 234 } 235 236 class CommandLineWebstoreInstall : public WebstoreStartupInstallerTest, 237 public content::NotificationObserver { 238 public: 239 CommandLineWebstoreInstall() : saw_install_(false), browser_open_count_(0) {} 240 virtual ~CommandLineWebstoreInstall() {} 241 242 virtual void SetUpOnMainThread() OVERRIDE { 243 WebstoreStartupInstallerTest::SetUpOnMainThread(); 244 registrar_.Add(this, 245 chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED, 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_DEPRECATED) { 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 base::CommandLine* command_line = base::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 base::CommandLine* command_line = base::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 base::CommandLine command_line_test1(base::CommandLine::NO_PROGRAM); 312 command_line_test1.AppendSwitchASCII(switches::kLimitedInstallFromWebstore, 313 "1"); 314 EXPECT_EQ("nckgahadagoaajjgafhacjanaoiihapd", 315 helper.WebStoreIdFromLimitedInstallCmdLine(command_line_test1)); 316 317 base::CommandLine command_line_test2(base::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 base::CommandLine* command_line = base::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