Home | History | Annotate | Download | only in webstore_private
      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 <vector>
      6 
      7 #include "base/files/file_path.h"
      8 #include "base/files/file_util.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/browser/extensions/api/management/management_api.h"
     13 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
     14 #include "chrome/browser/extensions/extension_apitest.h"
     15 #include "chrome/browser/extensions/extension_function_test_utils.h"
     16 #include "chrome/browser/extensions/extension_install_prompt.h"
     17 #include "chrome/browser/extensions/extension_install_ui.h"
     18 #include "chrome/browser/extensions/extension_service.h"
     19 #include "chrome/browser/extensions/webstore_installer.h"
     20 #include "chrome/browser/profiles/profile.h"
     21 #include "chrome/browser/ui/browser.h"
     22 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     23 #include "chrome/common/chrome_switches.h"
     24 #include "chrome/test/base/ui_test_utils.h"
     25 #include "content/public/browser/gpu_data_manager.h"
     26 #include "content/public/browser/notification_observer.h"
     27 #include "content/public/browser/notification_registrar.h"
     28 #include "content/public/test/browser_test_utils.h"
     29 #include "extensions/browser/extension_system.h"
     30 #include "gpu/config/gpu_feature_type.h"
     31 #include "gpu/config/gpu_info.h"
     32 #include "net/dns/mock_host_resolver.h"
     33 #include "ui/gl/gl_switches.h"
     34 
     35 using gpu::GpuFeatureType;
     36 
     37 namespace utils = extension_function_test_utils;
     38 
     39 namespace extensions {
     40 
     41 namespace {
     42 
     43 class WebstoreInstallListener : public WebstoreInstaller::Delegate {
     44  public:
     45   WebstoreInstallListener()
     46       : received_failure_(false), received_success_(false), waiting_(false) {}
     47 
     48   virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE {
     49     received_success_ = true;
     50     id_ = id;
     51 
     52     if (waiting_) {
     53       waiting_ = false;
     54       base::MessageLoopForUI::current()->Quit();
     55     }
     56   }
     57 
     58   virtual void OnExtensionInstallFailure(
     59       const std::string& id,
     60       const std::string& error,
     61       WebstoreInstaller::FailureReason reason) OVERRIDE {
     62     received_failure_ = true;
     63     id_ = id;
     64     error_ = error;
     65 
     66     if (waiting_) {
     67       waiting_ = false;
     68       base::MessageLoopForUI::current()->Quit();
     69     }
     70   }
     71 
     72   void Wait() {
     73     if (received_success_ || received_failure_)
     74       return;
     75 
     76     waiting_ = true;
     77     content::RunMessageLoop();
     78   }
     79   bool received_success() const { return received_success_; }
     80   const std::string& id() const { return id_; }
     81 
     82  private:
     83   bool received_failure_;
     84   bool received_success_;
     85   bool waiting_;
     86   std::string id_;
     87   std::string error_;
     88 };
     89 
     90 }  // namespace
     91 
     92 // A base class for tests below.
     93 class ExtensionWebstorePrivateApiTest : public ExtensionApiTest {
     94  public:
     95   ExtensionWebstorePrivateApiTest() {}
     96   virtual ~ExtensionWebstorePrivateApiTest() {}
     97 
     98   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     99     ExtensionApiTest::SetUpCommandLine(command_line);
    100     command_line->AppendSwitchASCII(
    101         switches::kAppsGalleryURL,
    102         "http://www.example.com/files/extensions/api_test");
    103   }
    104 
    105   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    106     ExtensionApiTest::SetUpInProcessBrowserTestFixture();
    107 
    108     // Start up the test server and get us ready for calling the install
    109     // API functions.
    110     host_resolver()->AddRule("www.example.com", "127.0.0.1");
    111     ASSERT_TRUE(StartSpawnedTestServer());
    112     ExtensionInstallUI::set_disable_failure_ui_for_tests();
    113   }
    114 
    115   virtual void SetUpOnMainThread() OVERRIDE {
    116     ExtensionApiTest::SetUpOnMainThread();
    117 
    118     ExtensionInstallPrompt::g_auto_confirm_for_tests =
    119         ExtensionInstallPrompt::ACCEPT;
    120 
    121     ASSERT_TRUE(webstore_install_dir_.CreateUniqueTempDir());
    122     webstore_install_dir_copy_ = webstore_install_dir_.path();
    123     WebstoreInstaller::SetDownloadDirectoryForTests(
    124         &webstore_install_dir_copy_);
    125   }
    126 
    127  protected:
    128   // Returns a test server URL, but with host 'www.example.com' so it matches
    129   // the web store app's extent that we set up via command line flags.
    130   GURL DoGetTestServerURL(const std::string& path) {
    131     GURL url = test_server()->GetURL(path);
    132 
    133     // Replace the host with 'www.example.com' so it matches the web store
    134     // app's extent.
    135     GURL::Replacements replace_host;
    136     std::string host_str("www.example.com");
    137     replace_host.SetHostStr(host_str);
    138 
    139     return url.ReplaceComponents(replace_host);
    140   }
    141 
    142   virtual GURL GetTestServerURL(const std::string& path) {
    143     return DoGetTestServerURL(
    144         std::string("files/extensions/api_test/webstore_private/") + path);
    145   }
    146 
    147   // Navigates to |page| and runs the Extension API test there. Any downloads
    148   // of extensions will return the contents of |crx_file|.
    149   bool RunInstallTest(const std::string& page, const std::string& crx_file) {
    150     // Auto-confirm the uninstallation dialog.
    151     ManagementUninstallFunction::SetAutoConfirmForTest(true);
    152 #if defined(OS_WIN) && !defined(NDEBUG)
    153     // See http://crbug.com/177163 for details.
    154     return true;
    155 #else
    156     GURL crx_url = GetTestServerURL(crx_file);
    157     CommandLine::ForCurrentProcess()->AppendSwitchASCII(
    158         switches::kAppsGalleryUpdateURL, crx_url.spec());
    159 
    160     GURL page_url = GetTestServerURL(page);
    161     return RunPageTest(page_url.spec());
    162 #endif
    163   }
    164 
    165   content::WebContents* GetWebContents() {
    166     return browser()->tab_strip_model()->GetActiveWebContents();
    167   }
    168 
    169   ExtensionService* service() {
    170     return ExtensionSystem::Get(browser()->profile())->extension_service();
    171   }
    172 
    173  private:
    174   base::ScopedTempDir webstore_install_dir_;
    175   // WebstoreInstaller needs a reference to a FilePath when setting the download
    176   // directory for testing.
    177   base::FilePath webstore_install_dir_copy_;
    178 };
    179 
    180 // Test cases for webstore origin frame blocking.
    181 // TODO(mkwst): Disabled until new X-Frame-Options behavior rolls into
    182 // Chromium, see crbug.com/226018.
    183 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
    184                        DISABLED_FrameWebstorePageBlocked) {
    185   base::string16 expected_title = base::UTF8ToUTF16("PASS: about:blank");
    186   base::string16 failure_title = base::UTF8ToUTF16("FAIL");
    187   content::TitleWatcher watcher(GetWebContents(), expected_title);
    188   watcher.AlsoWaitForTitle(failure_title);
    189   GURL url = test_server()->GetURL(
    190       "files/extensions/api_test/webstore_private/noframe.html");
    191   ui_test_utils::NavigateToURL(browser(), url);
    192   base::string16 final_title = watcher.WaitAndGetTitle();
    193   EXPECT_EQ(expected_title, final_title);
    194 }
    195 
    196 // TODO(mkwst): Disabled until new X-Frame-Options behavior rolls into
    197 // Chromium, see crbug.com/226018.
    198 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
    199                        DISABLED_FrameErrorPageBlocked) {
    200   base::string16 expected_title = base::UTF8ToUTF16("PASS: about:blank");
    201   base::string16 failure_title = base::UTF8ToUTF16("FAIL");
    202   content::TitleWatcher watcher(GetWebContents(), expected_title);
    203   watcher.AlsoWaitForTitle(failure_title);
    204   GURL url = test_server()->GetURL(
    205       "files/extensions/api_test/webstore_private/noframe2.html");
    206   ui_test_utils::NavigateToURL(browser(), url);
    207   base::string16 final_title = watcher.WaitAndGetTitle();
    208   EXPECT_EQ(expected_title, final_title);
    209 }
    210 
    211 // Test cases where the user accepts the install confirmation dialog.
    212 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallAccepted) {
    213   ASSERT_TRUE(RunInstallTest("accepted.html", "extension.crx"));
    214 }
    215 
    216 // Test having the default download directory missing.
    217 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MissingDownloadDir) {
    218   // Set a non-existent directory as the download path.
    219   base::ScopedTempDir temp_dir;
    220   EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
    221   base::FilePath missing_directory = temp_dir.Take();
    222   EXPECT_TRUE(base::DeleteFile(missing_directory, true));
    223   WebstoreInstaller::SetDownloadDirectoryForTests(&missing_directory);
    224 
    225   // Now run the install test, which should succeed.
    226   ASSERT_TRUE(RunInstallTest("accepted.html", "extension.crx"));
    227 
    228   // Cleanup.
    229   if (base::DirectoryExists(missing_directory))
    230     EXPECT_TRUE(base::DeleteFile(missing_directory, true));
    231 }
    232 
    233 // Tests passing a localized name.
    234 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallLocalized) {
    235   ASSERT_TRUE(RunInstallTest("localized.html", "localized_extension.crx"));
    236 }
    237 
    238 // Now test the case where the user cancels the confirmation dialog.
    239 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallCancelled) {
    240   ExtensionInstallPrompt::g_auto_confirm_for_tests =
    241       ExtensionInstallPrompt::CANCEL;
    242   ASSERT_TRUE(RunInstallTest("cancelled.html", "extension.crx"));
    243 }
    244 
    245 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IncorrectManifest1) {
    246   ASSERT_TRUE(RunInstallTest("incorrect_manifest1.html", "extension.crx"));
    247 }
    248 
    249 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IncorrectManifest2) {
    250   ASSERT_TRUE(RunInstallTest("incorrect_manifest2.html", "extension.crx"));
    251 }
    252 
    253 // Disabled: http://crbug.com/174399 and http://crbug.com/177163
    254 #if defined(OS_WIN) && (defined(USE_AURA) || !defined(NDEBUG))
    255 #define MAYBE_AppInstallBubble DISABLED_AppInstallBubble
    256 #else
    257 #define MAYBE_AppInstallBubble AppInstallBubble
    258 #endif
    259 
    260 // Tests that we can request an app installed bubble (instead of the default
    261 // UI when an app is installed).
    262 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest,
    263                        MAYBE_AppInstallBubble) {
    264   WebstoreInstallListener listener;
    265   WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener);
    266   ASSERT_TRUE(RunInstallTest("app_install_bubble.html", "app.crx"));
    267   listener.Wait();
    268   ASSERT_TRUE(listener.received_success());
    269   ASSERT_EQ("iladmdjkfniedhfhcfoefgojhgaiaccc", listener.id());
    270 }
    271 
    272 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IsInIncognitoMode) {
    273   GURL page_url = GetTestServerURL("incognito.html");
    274   ASSERT_TRUE(
    275       RunPageTest(page_url.spec(), ExtensionApiTest::kFlagUseIncognito));
    276 }
    277 
    278 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IsNotInIncognitoMode) {
    279   GURL page_url = GetTestServerURL("not_incognito.html");
    280   ASSERT_TRUE(RunPageTest(page_url.spec()));
    281 }
    282 
    283 // Fails often on Windows dbg bots. http://crbug.com/177163.
    284 #if defined(OS_WIN)
    285 #define MAYBE_IconUrl DISABLED_IconUrl
    286 #else
    287 #define MAYBE_IconUrl IconUrl
    288 #endif  // defined(OS_WIN)
    289 // Tests using the iconUrl parameter to the install function.
    290 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MAYBE_IconUrl) {
    291   ASSERT_TRUE(RunInstallTest("icon_url.html", "extension.crx"));
    292 }
    293 
    294 // http://crbug.com/177163
    295 #if defined(OS_WIN) && !defined(NDEBUG)
    296 #define MAYBE_BeginInstall DISABLED_BeginInstall
    297 #else
    298 #define MAYBE_BeginInstall BeginInstall
    299 #endif
    300 // Tests that the Approvals are properly created in beginInstall.
    301 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MAYBE_BeginInstall) {
    302   std::string appId = "iladmdjkfniedhfhcfoefgojhgaiaccc";
    303   std::string extensionId = "enfkhcelefdadlmkffamgdlgplcionje";
    304   ASSERT_TRUE(RunInstallTest("begin_install.html", "extension.crx"));
    305 
    306   scoped_ptr<WebstoreInstaller::Approval> approval =
    307       WebstorePrivateApi::PopApprovalForTesting(browser()->profile(), appId);
    308   EXPECT_EQ(appId, approval->extension_id);
    309   EXPECT_TRUE(approval->use_app_installed_bubble);
    310   EXPECT_FALSE(approval->skip_post_install_ui);
    311   EXPECT_EQ("2", approval->authuser);
    312   EXPECT_EQ(browser()->profile(), approval->profile);
    313 
    314   approval = WebstorePrivateApi::PopApprovalForTesting(
    315       browser()->profile(), extensionId);
    316   EXPECT_EQ(extensionId, approval->extension_id);
    317   EXPECT_FALSE(approval->use_app_installed_bubble);
    318   EXPECT_FALSE(approval->skip_post_install_ui);
    319   EXPECT_TRUE(approval->authuser.empty());
    320   EXPECT_EQ(browser()->profile(), approval->profile);
    321 }
    322 
    323 // http://crbug.com/177163
    324 #if defined(OS_WIN) && !defined(NDEBUG)
    325 #define MAYBE_InstallTheme DISABLED_InstallTheme
    326 #else
    327 #define MAYBE_InstallTheme InstallTheme
    328 #endif
    329 // Tests that themes are installed without an install prompt.
    330 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MAYBE_InstallTheme) {
    331   WebstoreInstallListener listener;
    332   WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener);
    333   ASSERT_TRUE(RunInstallTest("theme.html", "../../theme.crx"));
    334   listener.Wait();
    335   ASSERT_TRUE(listener.received_success());
    336   ASSERT_EQ("iamefpfkojoapidjnbafmgkgncegbkad", listener.id());
    337 }
    338 
    339 // Tests that an error is properly reported when an empty crx is returned.
    340 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, EmptyCrx) {
    341   ASSERT_TRUE(RunInstallTest("empty.html", "empty.crx"));
    342 }
    343 
    344 class ExtensionWebstoreGetWebGLStatusTest : public InProcessBrowserTest {
    345  protected:
    346   void RunTest(bool webgl_allowed) {
    347     // If Gpu access is disallowed then WebGL will not be available.
    348     if (!content::GpuDataManager::GetInstance()->GpuAccessAllowed(NULL))
    349       webgl_allowed = false;
    350 
    351     static const char kEmptyArgs[] = "[]";
    352     static const char kWebGLStatusAllowed[] = "webgl_allowed";
    353     static const char kWebGLStatusBlocked[] = "webgl_blocked";
    354     scoped_refptr<WebstorePrivateGetWebGLStatusFunction> function =
    355         new WebstorePrivateGetWebGLStatusFunction();
    356     scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
    357             function.get(), kEmptyArgs, browser()));
    358     ASSERT_TRUE(result);
    359     EXPECT_EQ(base::Value::TYPE_STRING, result->GetType());
    360     std::string webgl_status;
    361     EXPECT_TRUE(result->GetAsString(&webgl_status));
    362     EXPECT_STREQ(webgl_allowed ? kWebGLStatusAllowed : kWebGLStatusBlocked,
    363                  webgl_status.c_str());
    364   }
    365 };
    366 
    367 // Tests getWebGLStatus function when WebGL is allowed.
    368 IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest, Allowed) {
    369   bool webgl_allowed = true;
    370   RunTest(webgl_allowed);
    371 }
    372 
    373 // Tests getWebGLStatus function when WebGL is blacklisted.
    374 IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest, Blocked) {
    375   static const std::string json_blacklist =
    376       "{\n"
    377       "  \"name\": \"gpu blacklist\",\n"
    378       "  \"version\": \"1.0\",\n"
    379       "  \"entries\": [\n"
    380       "    {\n"
    381       "      \"id\": 1,\n"
    382       "      \"features\": [\n"
    383       "        \"webgl\"\n"
    384       "      ]\n"
    385       "    }\n"
    386       "  ]\n"
    387       "}";
    388   gpu::GPUInfo gpu_info;
    389   content::GpuDataManager::GetInstance()->InitializeForTesting(
    390       json_blacklist, gpu_info);
    391   EXPECT_TRUE(content::GpuDataManager::GetInstance()->IsFeatureBlacklisted(
    392       gpu::GPU_FEATURE_TYPE_WEBGL));
    393 
    394   bool webgl_allowed = false;
    395   RunTest(webgl_allowed);
    396 }
    397 
    398 class EphemeralAppWebstorePrivateApiTest
    399     : public ExtensionWebstorePrivateApiTest {
    400  public:
    401   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    402     ExtensionWebstorePrivateApiTest::SetUpInProcessBrowserTestFixture();
    403 
    404     net::HostPortPair host_port = test_server()->host_port_pair();
    405     std::string test_gallery_url = base::StringPrintf(
    406         "http://www.example.com:%d/files/extensions/platform_apps/"
    407         "ephemeral_launcher",
    408         host_port.port());
    409     CommandLine::ForCurrentProcess()->AppendSwitchASCII(
    410         switches::kAppsGalleryURL, test_gallery_url);
    411   }
    412 
    413   virtual GURL GetTestServerURL(const std::string& path) OVERRIDE {
    414     return DoGetTestServerURL(
    415         std::string("files/extensions/platform_apps/ephemeral_launcher/") +
    416         path);
    417   }
    418 };
    419 
    420 // Run tests when the --enable-ephemeral-apps switch is not enabled.
    421 IN_PROC_BROWSER_TEST_F(EphemeralAppWebstorePrivateApiTest,
    422                        EphemeralAppsFeatureDisabled) {
    423   ASSERT_TRUE(RunInstallTest("webstore_launch_disabled.html", "app.crx"));
    424 }
    425 
    426 // Run tests when the --enable-ephemeral-apps switch is enabled.
    427 IN_PROC_BROWSER_TEST_F(EphemeralAppWebstorePrivateApiTest, LaunchEphemeralApp) {
    428   CommandLine::ForCurrentProcess()->AppendSwitch(
    429       switches::kEnableEphemeralApps);
    430   ASSERT_TRUE(RunInstallTest("webstore_launch_app.html", "app.crx"));
    431 }
    432 
    433 }  // namespace extensions
    434