extension_loading_browsertest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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// This file contains tests for extension loading, reloading, and 6// unloading behavior. 7 8#include "base/json/json_writer.h" 9#include "base/run_loop.h" 10#include "base/safe_numerics.h" 11#include "base/test/values_test_util.h" 12#include "chrome/browser/extensions/extension_browsertest.h" 13#include "chrome/browser/extensions/extension_creator.h" 14#include "chrome/browser/extensions/extension_service.h" 15#include "chrome/browser/extensions/extension_system.h" 16#include "chrome/browser/ui/tabs/tab_strip_model.h" 17#include "chrome/test/base/in_process_browser_test.h" 18#include "chrome/test/base/ui_test_utils.h" 19#include "net/test/embedded_test_server/embedded_test_server.h" 20#include "testing/gmock/include/gmock/gmock.h" 21 22namespace extensions { 23namespace { 24 25// Provides a temporary directory to build an extension into. This lets all of 26// an extension's code live inside the test instead of in a separate directory. 27class TestExtensionDir { 28 public: 29 TestExtensionDir() { 30 EXPECT_TRUE(dir_.CreateUniqueTempDir()); 31 EXPECT_TRUE(crx_dir_.CreateUniqueTempDir()); 32 } 33 34 // Writes |contents| to path()/filename, overwriting anything that was already 35 // there. 36 void WriteFile(base::FilePath::StringType filename, 37 base::StringPiece contents) { 38 EXPECT_EQ( 39 base::checked_numeric_cast<int>(contents.size()), 40 file_util::WriteFile( 41 dir_.path().Append(filename), contents.data(), contents.size())); 42 } 43 44 // Converts |value| to JSON, and then writes it to path()/filename with 45 // WriteFile(). 46 void WriteJson(base::FilePath::StringType filename, const Value& value) { 47 std::string json; 48 base::JSONWriter::Write(&value, &json); 49 WriteFile(filename, json); 50 } 51 52 // This function packs the extension into a .crx, and returns the path to that 53 // .crx. Multiple calls to Pack() will produce extensions with the same ID. 54 base::FilePath Pack() { 55 ExtensionCreator creator; 56 base::FilePath crx_path = 57 crx_dir_.path().Append(FILE_PATH_LITERAL("ext.crx")); 58 base::FilePath pem_path = 59 crx_dir_.path().Append(FILE_PATH_LITERAL("ext.pem")); 60 base::FilePath pem_in_path, pem_out_path; 61 if (file_util::PathExists(pem_path)) 62 pem_in_path = pem_path; 63 else 64 pem_out_path = pem_path; 65 if (!creator.Run(dir_.path(), 66 crx_path, 67 pem_in_path, 68 pem_out_path, 69 ExtensionCreator::kOverwriteCRX)) { 70 ADD_FAILURE() 71 << "ExtensionCreator::Run() failed: " << creator.error_message(); 72 return base::FilePath(); 73 } 74 if (!file_util::PathExists(crx_path)) { 75 ADD_FAILURE() << crx_path.value() << " was not created."; 76 return base::FilePath(); 77 } 78 return crx_path; 79 } 80 81 private: 82 // Stores files that make up the extension. 83 base::ScopedTempDir dir_; 84 // Stores the generated .crx and .pem. 85 base::ScopedTempDir crx_dir_; 86}; 87 88class ExtensionLoadingTest : public ExtensionBrowserTest { 89}; 90 91// Check the fix for http://crbug.com/178542. 92IN_PROC_BROWSER_TEST_F(ExtensionLoadingTest, 93 UpgradeAfterNavigatingFromOverriddenNewTabPage) { 94 embedded_test_server()->ServeFilesFromDirectory( 95 base::FilePath(FILE_PATH_LITERAL("chrome/test/data"))); 96 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 97 98 TestExtensionDir extension_dir; 99 scoped_ptr<base::Value> manifest = 100 base::test::ParseJson("{" 101 " \"name\": \"Overrides New Tab\"," 102 " \"version\": \"1\"," 103 " \"description\": \"Overrides New Tab\"," 104 " \"manifest_version\": 2," 105 " \"background\": {" 106 " \"persistent\": false," 107 " \"scripts\": [\"event.js\"]" 108 " }," 109 " \"chrome_url_overrides\": {" 110 " \"newtab\": \"newtab.html\"" 111 " }" 112 "}"); 113 extension_dir.WriteJson(FILE_PATH_LITERAL("manifest.json"), *manifest); 114 extension_dir.WriteFile(FILE_PATH_LITERAL("event.js"), ""); 115 extension_dir.WriteFile(FILE_PATH_LITERAL("newtab.html"), 116 "<h1>Overridden New Tab Page</h1>"); 117 118 const Extension* new_tab_extension = 119 InstallExtension(extension_dir.Pack(), 1 /*new install*/); 120 ASSERT_TRUE(new_tab_extension); 121 122 // Visit the New Tab Page to get a renderer using the extension into history. 123 ui_test_utils::NavigateToURL(browser(), GURL("chrome://newtab")); 124 125 // Navigate that tab to a non-extension URL to swap out the extension's 126 // renderer. 127 const GURL test_link_from_NTP = 128 embedded_test_server()->GetURL("/README.chromium"); 129 EXPECT_THAT(test_link_from_NTP.spec(), testing::EndsWith("/README.chromium")) 130 << "Check that the test server started."; 131 NavigateInRenderer(browser()->tab_strip_model()->GetActiveWebContents(), 132 test_link_from_NTP); 133 134 // Increase the extension's version. 135 static_cast<base::DictionaryValue&>(*manifest).SetString("version", "2"); 136 extension_dir.WriteJson(FILE_PATH_LITERAL("manifest.json"), *manifest); 137 138 // Upgrade the extension. 139 new_tab_extension = UpdateExtension( 140 new_tab_extension->id(), extension_dir.Pack(), 0 /*expected upgrade*/); 141 EXPECT_THAT(new_tab_extension->version()->components(), 142 testing::ElementsAre(2)); 143 144 // The extension takes a couple round-trips to the renderer in order 145 // to crash, so open a new tab to wait long enough. 146 AddTabAtIndex(browser()->tab_strip_model()->count(), 147 GURL("http://www.google.com/"), 148 content::PAGE_TRANSITION_TYPED); 149 150 // Check that the extension hasn't crashed. 151 ExtensionService* service = 152 ExtensionSystem::Get(profile())->extension_service(); 153 EXPECT_EQ(0U, service->terminated_extensions()->size()); 154 EXPECT_TRUE(service->extensions()->Contains(new_tab_extension->id())); 155} 156 157} // namespace 158} // namespace extensions 159