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