1 // Copyright (c) 2011 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/command_line.h"
8 #include "base/file_path.h"
9 #include "base/file_util.h"
10 #include "base/path_service.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/user_script_master.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/common/chrome_paths.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/test/in_process_browser_test.h"
18 #include "chrome/test/ui_test_utils.h"
19 #include "content/browser/tab_contents/tab_contents.h"
20 #include "content/common/notification_details.h"
21 #include "content/common/notification_type.h"
22 #include "net/base/net_util.h"
23
24 // This file contains high-level startup tests for the extensions system. We've
25 // had many silly bugs where command line flags did not get propagated correctly
26 // into the services, so we didn't start correctly.
27
28 class ExtensionStartupTestBase : public InProcessBrowserTest {
29 public:
ExtensionStartupTestBase()30 ExtensionStartupTestBase() : enable_extensions_(false) {
31 num_expected_extensions_ = 3;
32 }
33
34 protected:
35 // InProcessBrowserTest
SetUpCommandLine(CommandLine * command_line)36 virtual void SetUpCommandLine(CommandLine* command_line) {
37 EnableDOMAutomation();
38
39 FilePath profile_dir;
40 PathService::Get(chrome::DIR_USER_DATA, &profile_dir);
41 profile_dir = profile_dir.AppendASCII("Default");
42 file_util::CreateDirectory(profile_dir);
43
44 preferences_file_ = profile_dir.AppendASCII("Preferences");
45 user_scripts_dir_ = profile_dir.AppendASCII("User Scripts");
46 extensions_dir_ = profile_dir.AppendASCII("Extensions");
47
48 if (enable_extensions_) {
49 if (load_extension_.empty()) {
50 FilePath src_dir;
51 PathService::Get(chrome::DIR_TEST_DATA, &src_dir);
52 src_dir = src_dir.AppendASCII("extensions").AppendASCII("good");
53
54 file_util::CopyFile(src_dir.AppendASCII("Preferences"),
55 preferences_file_);
56 file_util::CopyDirectory(src_dir.AppendASCII("Extensions"),
57 profile_dir, true); // recursive
58 }
59 } else {
60 command_line->AppendSwitch(switches::kDisableExtensions);
61 }
62
63 if (!load_extension_.empty()) {
64 command_line->AppendSwitchPath(switches::kLoadExtension, load_extension_);
65 command_line->AppendSwitch(switches::kDisableExtensionsFileAccessCheck);
66 }
67 }
68
TearDown()69 virtual void TearDown() {
70 EXPECT_TRUE(file_util::Delete(preferences_file_, false));
71
72 // TODO(phajdan.jr): Check return values of the functions below, carefully.
73 file_util::Delete(user_scripts_dir_, true);
74 file_util::Delete(extensions_dir_, true);
75
76 InProcessBrowserTest::TearDown();
77 }
78
WaitForServicesToStart(int num_expected_extensions,bool expect_extensions_enabled)79 void WaitForServicesToStart(int num_expected_extensions,
80 bool expect_extensions_enabled) {
81 ExtensionService* service = browser()->profile()->GetExtensionService();
82
83 // Count the number of non-component extensions.
84 int found_extensions = 0;
85 for (size_t i = 0; i < service->extensions()->size(); i++)
86 if (service->extensions()->at(i)->location() != Extension::COMPONENT)
87 found_extensions++;
88
89 ASSERT_EQ(static_cast<uint32>(num_expected_extensions),
90 static_cast<uint32>(found_extensions));
91 ASSERT_EQ(expect_extensions_enabled, service->extensions_enabled());
92
93 UserScriptMaster* master = browser()->profile()->GetUserScriptMaster();
94 if (!master->ScriptsReady()) {
95 ui_test_utils::WaitForNotification(
96 NotificationType::USER_SCRIPTS_UPDATED);
97 }
98 ASSERT_TRUE(master->ScriptsReady());
99 }
100
TestInjection(bool expect_css,bool expect_script)101 void TestInjection(bool expect_css, bool expect_script) {
102 // Load a page affected by the content script and test to see the effect.
103 FilePath test_file;
104 PathService::Get(chrome::DIR_TEST_DATA, &test_file);
105 test_file = test_file.AppendASCII("extensions")
106 .AppendASCII("test_file.html");
107
108 ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(test_file));
109
110 bool result = false;
111 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
112 browser()->GetSelectedTabContents()->render_view_host(), L"",
113 L"window.domAutomationController.send("
114 L"document.defaultView.getComputedStyle(document.body, null)."
115 L"getPropertyValue('background-color') == 'rgb(245, 245, 220)')",
116 &result));
117 EXPECT_EQ(expect_css, result);
118
119 result = false;
120 ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
121 browser()->GetSelectedTabContents()->render_view_host(), L"",
122 L"window.domAutomationController.send(document.title == 'Modified')",
123 &result));
124 EXPECT_EQ(expect_script, result);
125 }
126
127 FilePath preferences_file_;
128 FilePath extensions_dir_;
129 FilePath user_scripts_dir_;
130 bool enable_extensions_;
131 FilePath load_extension_;
132
133 int num_expected_extensions_;
134 };
135
136
137 // ExtensionsStartupTest
138 // Ensures that we can startup the browser with --enable-extensions and some
139 // extensions installed and see them run and do basic things.
140
141 class ExtensionsStartupTest : public ExtensionStartupTestBase {
142 public:
ExtensionsStartupTest()143 ExtensionsStartupTest() {
144 enable_extensions_ = true;
145 }
146 };
147
IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest,Test)148 IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, Test) {
149 WaitForServicesToStart(num_expected_extensions_, true);
150 TestInjection(true, true);
151 }
152
153 // Sometimes times out on Mac. http://crbug.com/48151
154 #if defined(OS_MACOSX)
155 #define MAYBE_NoFileAccess DISABLED_NoFileAccess
156 #else
157 #define MAYBE_NoFileAccess NoFileAccess
158 #endif
159 // Tests that disallowing file access on an extension prevents it from injecting
160 // script into a page with a file URL.
IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest,MAYBE_NoFileAccess)161 IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, MAYBE_NoFileAccess) {
162 WaitForServicesToStart(num_expected_extensions_, true);
163
164 ExtensionService* service = browser()->profile()->GetExtensionService();
165 for (size_t i = 0; i < service->extensions()->size(); ++i) {
166 if (service->extensions()->at(i)->location() == Extension::COMPONENT)
167 continue;
168 if (service->AllowFileAccess(service->extensions()->at(i))) {
169 service->SetAllowFileAccess(service->extensions()->at(i), false);
170 ui_test_utils::WaitForNotification(
171 NotificationType::USER_SCRIPTS_UPDATED);
172 }
173 }
174
175 TestInjection(false, false);
176 }
177
178 // ExtensionsLoadTest
179 // Ensures that we can startup the browser with --load-extension and see them
180 // run.
181
182 class ExtensionsLoadTest : public ExtensionStartupTestBase {
183 public:
ExtensionsLoadTest()184 ExtensionsLoadTest() {
185 enable_extensions_ = true;
186 PathService::Get(chrome::DIR_TEST_DATA, &load_extension_);
187 load_extension_ = load_extension_
188 .AppendASCII("extensions")
189 .AppendASCII("good")
190 .AppendASCII("Extensions")
191 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
192 .AppendASCII("1.0.0.0");
193 }
194 };
195
IN_PROC_BROWSER_TEST_F(ExtensionsLoadTest,Test)196 IN_PROC_BROWSER_TEST_F(ExtensionsLoadTest, Test) {
197 WaitForServicesToStart(1, true);
198 TestInjection(true, true);
199 }
200