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
28class ExtensionStartupTestBase : public InProcessBrowserTest {
29 public:
30  ExtensionStartupTestBase() : enable_extensions_(false) {
31    num_expected_extensions_ = 3;
32  }
33
34 protected:
35  // InProcessBrowserTest
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
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
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
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
141class ExtensionsStartupTest : public ExtensionStartupTestBase {
142 public:
143  ExtensionsStartupTest() {
144    enable_extensions_ = true;
145  }
146};
147
148IN_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.
161IN_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
182class ExtensionsLoadTest : public ExtensionStartupTestBase {
183 public:
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
196IN_PROC_BROWSER_TEST_F(ExtensionsLoadTest, Test) {
197  WaitForServicesToStart(1, true);
198  TestInjection(true, true);
199}
200