active_script_controller_browsertest.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// found in the LICENSE file.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/files/file_path.h"
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/macros.h"
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "base/strings/stringprintf.h"
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/active_script_controller.h"
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/extension_action.h"
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/extension_browsertest.h"
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h"
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/extensions/test_extension_dir.h"
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "chrome/test/base/ui_test_utils.h"
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "content/public/test/browser_test_utils.h"
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "extensions/common/feature_switch.h"
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "extensions/common/switches.h"
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "extensions/test/extension_test_message_listener.h"
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "net/test/embedded_test_server/embedded_test_server.h"
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace extensions {
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace {
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const char kAllHostsScheme[] = "*://*/*";
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const char kExplicitHostsScheme[] = "http://127.0.0.1/*";
2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)const char kBackgroundScript[] =
30d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)    "\"background\": {\"scripts\": [\"script.js\"]}";
3153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)const char kBackgroundScriptSource[] =
3209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    "var listener = function(tabId) {\n"
3310f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    "  chrome.tabs.onUpdated.removeListener(listener);\n"
3453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    "  chrome.tabs.executeScript(tabId, {\n"
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    "    code: \"chrome.test.sendMessage('inject succeeded');\"\n"
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "  });"
37c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    "};\n"
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    "chrome.tabs.onUpdated.addListener(listener);";
397757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdochconst char kContentScriptSource[] =
401e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    "chrome.test.sendMessage('inject succeeded');";
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const char kInjectSucceeded[] = "inject succeeded";
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
44197021e6b966cfb06891637935ef33fff06433d1Ben Murdochenum InjectionType {
455d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)  CONTENT_SCRIPT,
467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci  EXECUTE_SCRIPT
47d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)};
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
495d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)enum HostType {
5009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)  ALL_HOSTS,
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  EXPLICIT_HOSTS
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
535d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)
545d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)enum RequiresConsent {
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  REQUIRES_CONSENT,
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  DOES_NOT_REQUIRE_CONSENT
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)};
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Runs all pending tasks in the renderer associated with |web_contents|.
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Returns true on success.
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool RunAllPendingInRenderer(content::WebContents* web_contents) {
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // This is slight hack to achieve a RunPendingInRenderer() method. Since IPCs
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // are sent synchronously, anything started prior to this method will finish
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // before this method returns (as content::ExecuteScript() is synchronous).
657757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch  return content::ExecuteScript(web_contents, "1 == 1;");
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}  // namespace
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class ActiveScriptControllerBrowserTest : public ExtensionBrowserTest {
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) public:
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ActiveScriptControllerBrowserTest() {}
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE;
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  virtual void TearDownOnMainThread() OVERRIDE;
765d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)
775d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)  // Returns an extension with the given |host_type| and |injection_type|. If
78a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch  // one already exists, the existing extension will be returned. Othewrwise,
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // one will be created.
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // This could potentially return NULL if LoadExtension() fails.
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  const Extension* CreateExtension(HostType host_type,
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                                   InjectionType injection_type);
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
841e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) private:
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ScopedVector<TestExtensionDir> test_extension_dirs_;
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  std::vector<const Extension*> extensions_;
8707a852d8c1953036774d8f3b65d18dcfea3bb4a2Ben Murdoch};
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void ActiveScriptControllerBrowserTest::SetUpCommandLine(
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    base::CommandLine* command_line) {
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  ExtensionBrowserTest::SetUpCommandLine(command_line);
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // We append the actual switch to the commandline because it needs to be
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // passed over to the renderer, which a FeatureSwitch::ScopedOverride will
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  // not do.
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  command_line->AppendSwitch(switches::kEnableScriptsRequireAction);
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void ActiveScriptControllerBrowserTest::TearDownOnMainThread() {
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  test_extension_dirs_.clear();
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
102d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)const Extension* ActiveScriptControllerBrowserTest::CreateExtension(
10309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    HostType host_type, InjectionType injection_type) {
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  std::string name =
1051e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)      base::StringPrintf(
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          "%s %s",
1075d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)          injection_type == CONTENT_SCRIPT ?
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)              "content_script" : "execute_script",
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)          host_type == ALL_HOSTS ? "all_hosts" : "explicit_hosts");
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  const char* permission_scheme =
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      host_type == ALL_HOSTS ? kAllHostsScheme : kExplicitHostsScheme;
1135d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  std::string permissions = base::StringPrintf(
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)      "\"permissions\": [\"tabs\", \"%s\"]", permission_scheme);
116926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
1175d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)  std::string scripts;
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  std::string script_source;
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)  if (injection_type == CONTENT_SCRIPT) {
120c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    scripts = base::StringPrintf(
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        "\"content_scripts\": ["
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        " {"
123        "  \"matches\": [\"%s\"],"
124        "  \"js\": [\"script.js\"],"
125        "  \"run_at\": \"document_start\""
126        " }"
127        "]",
128        permission_scheme);
129  } else {
130    scripts = kBackgroundScript;
131  }
132
133  std::string manifest = base::StringPrintf(
134      "{"
135      " \"name\": \"%s\","
136      " \"version\": \"1.0\","
137      " \"manifest_version\": 2,"
138      " %s,"
139      " %s"
140      "}",
141      name.c_str(),
142      permissions.c_str(),
143      scripts.c_str());
144
145  scoped_ptr<TestExtensionDir> dir(new TestExtensionDir);
146  dir->WriteManifest(manifest);
147  dir->WriteFile(FILE_PATH_LITERAL("script.js"),
148                 injection_type == CONTENT_SCRIPT ? kContentScriptSource :
149                                                    kBackgroundScriptSource);
150
151  const Extension* extension = LoadExtension(dir->unpacked_path());
152  if (extension) {
153    test_extension_dirs_.push_back(dir.release());
154    extensions_.push_back(extension);
155  }
156
157  // If extension is NULL here, it will be caught later in the test.
158  return extension;
159}
160
161class ActiveScriptTester {
162 public:
163  ActiveScriptTester(const std::string& name,
164                     const Extension* extension,
165                     Browser* browser,
166                     RequiresConsent requires_consent,
167                     InjectionType type);
168  ~ActiveScriptTester();
169
170  testing::AssertionResult Verify();
171
172 private:
173  // Returns the active script controller, or NULL if one does not exist.
174  ActiveScriptController* GetActiveScriptController();
175
176  // Returns true if the extension has a pending request with the active script
177  // controller.
178  bool WantsToRun();
179
180  // The name of the extension, and also the message it sends.
181  std::string name_;
182
183  // The extension associated with this tester.
184  const Extension* extension_;
185
186  // The browser the tester is running in.
187  Browser* browser_;
188
189  // Whether or not the extension has permission to run the script without
190  // asking the user.
191  RequiresConsent requires_consent_;
192
193  // The type of injection this tester uses.
194  InjectionType type_;
195
196  // All of these extensions should inject a script (either through content
197  // scripts or through chrome.tabs.executeScript()) that sends a message with
198  // the |kInjectSucceeded| message.
199  linked_ptr<ExtensionTestMessageListener> inject_success_listener_;
200};
201
202ActiveScriptTester::ActiveScriptTester(const std::string& name,
203                                       const Extension* extension,
204                                       Browser* browser,
205                                       RequiresConsent requires_consent,
206                                       InjectionType type)
207    : name_(name),
208      extension_(extension),
209      browser_(browser),
210      requires_consent_(requires_consent),
211      type_(type),
212      inject_success_listener_(
213          new ExtensionTestMessageListener(kInjectSucceeded,
214                                           false /* won't reply */)) {
215  inject_success_listener_->set_extension_id(extension->id());
216}
217
218ActiveScriptTester::~ActiveScriptTester() {
219}
220
221testing::AssertionResult ActiveScriptTester::Verify() {
222  if (!extension_)
223    return testing::AssertionFailure() << "Could not load extension: " << name_;
224
225  content::WebContents* web_contents =
226      browser_ ? browser_->tab_strip_model()->GetActiveWebContents() : NULL;
227  if (!web_contents)
228    return testing::AssertionFailure() << "No web contents.";
229
230  // Give the extension plenty of time to inject.
231  if (!RunAllPendingInRenderer(web_contents))
232    return testing::AssertionFailure() << "Could not run pending in renderer.";
233
234  // Make sure all running tasks are complete.
235  content::RunAllPendingInMessageLoop();
236
237  ActiveScriptController* controller = GetActiveScriptController();
238  if (!controller)
239    return testing::AssertionFailure() << "Could not find controller.";
240
241  bool wants_to_run = WantsToRun();
242
243  // An extension should have an action displayed iff it requires user consent.
244  if ((requires_consent_ == REQUIRES_CONSENT && !wants_to_run) ||
245      (requires_consent_ == DOES_NOT_REQUIRE_CONSENT && wants_to_run)) {
246    return testing::AssertionFailure()
247        << "Improper wants to run for " << name_ << ": expected "
248        << (requires_consent_ == REQUIRES_CONSENT) << ", found "
249        << wants_to_run;
250  }
251
252  // If the extension has permission, we should be able to simply wait for it
253  // to execute.
254  if (requires_consent_ == DOES_NOT_REQUIRE_CONSENT) {
255    inject_success_listener_->WaitUntilSatisfied();
256    return testing::AssertionSuccess();
257  }
258
259  // Otherwise, we don't have permission, and have to grant it. Ensure the
260  // script has *not* already executed.
261  if (inject_success_listener_->was_satisfied()) {
262    return testing::AssertionFailure() <<
263        name_ << "'s script ran without permission.";
264  }
265
266  // If we reach this point, we should always want to run.
267  DCHECK(wants_to_run);
268
269  // Grant permission by clicking on the extension action.
270  controller->OnClicked(extension_);
271
272  // Now, the extension should be able to inject the script.
273  inject_success_listener_->WaitUntilSatisfied();
274
275  // The extension should no longer want to run.
276  wants_to_run = WantsToRun();
277  if (wants_to_run) {
278    return testing::AssertionFailure()
279        << "Extension " << name_ << " still wants to run after injecting.";
280  }
281
282  return testing::AssertionSuccess();
283}
284
285ActiveScriptController* ActiveScriptTester::GetActiveScriptController() {
286  content::WebContents* web_contents =
287      browser_ ? browser_->tab_strip_model()->GetActiveWebContents() : NULL;
288
289  if (!web_contents)
290    return NULL;
291
292  TabHelper* tab_helper = TabHelper::FromWebContents(web_contents);
293  return tab_helper ? tab_helper->active_script_controller() : NULL;
294}
295
296bool ActiveScriptTester::WantsToRun() {
297  ActiveScriptController* controller = GetActiveScriptController();
298  return controller ? controller->WantsToRun(extension_) : false;
299}
300
301IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest,
302                       ActiveScriptsAreDisplayedAndDelayExecution) {
303  base::FilePath active_script_path =
304      test_data_dir_.AppendASCII("active_script");
305
306  const char* kExtensionNames[] = {
307      "inject_scripts_all_hosts",
308      "inject_scripts_explicit_hosts",
309      "content_scripts_all_hosts",
310      "content_scripts_explicit_hosts"
311  };
312
313  // First, we load up three extensions:
314  // - An extension that injects scripts into all hosts,
315  // - An extension that injects scripts into explicit hosts,
316  // - An extension with a content script that runs on all hosts,
317  // - An extension with a content script that runs on explicit hosts.
318  // The extensions that operate on explicit hosts have permission; the ones
319  // that request all hosts require user consent.
320  ActiveScriptTester testers[] = {
321      ActiveScriptTester(
322          kExtensionNames[0],
323          CreateExtension(ALL_HOSTS, EXECUTE_SCRIPT),
324          browser(),
325          REQUIRES_CONSENT,
326          EXECUTE_SCRIPT),
327      ActiveScriptTester(
328          kExtensionNames[1],
329          CreateExtension(EXPLICIT_HOSTS, EXECUTE_SCRIPT),
330          browser(),
331          DOES_NOT_REQUIRE_CONSENT,
332          EXECUTE_SCRIPT),
333      ActiveScriptTester(
334          kExtensionNames[2],
335          CreateExtension(ALL_HOSTS, CONTENT_SCRIPT),
336          browser(),
337          REQUIRES_CONSENT,
338          CONTENT_SCRIPT),
339      ActiveScriptTester(
340          kExtensionNames[3],
341          CreateExtension(EXPLICIT_HOSTS, CONTENT_SCRIPT),
342          browser(),
343          DOES_NOT_REQUIRE_CONSENT,
344          CONTENT_SCRIPT),
345  };
346
347  // Navigate to an URL (which matches the explicit host specified in the
348  // extension content_scripts_explicit_hosts). All four extensions should
349  // inject the script.
350  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
351  ui_test_utils::NavigateToURL(
352      browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
353
354  for (size_t i = 0u; i < arraysize(testers); ++i)
355    EXPECT_TRUE(testers[i].Verify()) << kExtensionNames[i];
356}
357
358// Test that removing an extension with pending injections a) removes the
359// pending injections for that extension, and b) does not affect pending
360// injections for other extensions.
361IN_PROC_BROWSER_TEST_F(ActiveScriptControllerBrowserTest,
362                       RemoveExtensionWithPendingInjections) {
363  // Load up two extensions, each with content scripts.
364  const Extension* extension1 = CreateExtension(ALL_HOSTS, CONTENT_SCRIPT);
365  ASSERT_TRUE(extension1);
366  const Extension* extension2 = CreateExtension(ALL_HOSTS, CONTENT_SCRIPT);
367  ASSERT_TRUE(extension2);
368
369  ASSERT_NE(extension1->id(), extension2->id());
370
371  content::WebContents* web_contents =
372      browser()->tab_strip_model()->GetActiveWebContents();
373  ASSERT_TRUE(web_contents);
374  ActiveScriptController* active_script_controller =
375      ActiveScriptController::GetForWebContents(web_contents);
376  ASSERT_TRUE(active_script_controller);
377
378  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
379  ui_test_utils::NavigateToURL(
380      browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
381
382  // Both extensions should have pending requests.
383  EXPECT_TRUE(active_script_controller->WantsToRun(extension1));
384  EXPECT_TRUE(active_script_controller->WantsToRun(extension2));
385
386  // Unload one of the extensions.
387  UnloadExtension(extension2->id());
388
389  EXPECT_TRUE(RunAllPendingInRenderer(web_contents));
390
391  // We should have pending requests for extension1, but not the removed
392  // extension2.
393  EXPECT_TRUE(active_script_controller->WantsToRun(extension1));
394  EXPECT_FALSE(active_script_controller->WantsToRun(extension2));
395
396  // We should still be able to run the request for extension1.
397  ExtensionTestMessageListener inject_success_listener(
398      new ExtensionTestMessageListener(kInjectSucceeded,
399                                       false /* won't reply */));
400  inject_success_listener.set_extension_id(extension1->id());
401  active_script_controller->OnClicked(extension1);
402  inject_success_listener.WaitUntilSatisfied();
403}
404
405// A version of the test with the flag off, in order to test that everything
406// still works as expected.
407class FlagOffActiveScriptControllerBrowserTest
408    : public ActiveScriptControllerBrowserTest {
409 private:
410  // Simply don't append the flag.
411  virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
412    ExtensionBrowserTest::SetUpCommandLine(command_line);
413  }
414};
415
416IN_PROC_BROWSER_TEST_F(FlagOffActiveScriptControllerBrowserTest,
417                       ScriptsExecuteWhenFlagAbsent) {
418  const char* kExtensionNames[] = {
419    "content_scripts_all_hosts",
420    "inject_scripts_all_hosts",
421  };
422  ActiveScriptTester testers[] = {
423    ActiveScriptTester(
424          kExtensionNames[0],
425          CreateExtension(ALL_HOSTS, CONTENT_SCRIPT),
426          browser(),
427          DOES_NOT_REQUIRE_CONSENT,
428          CONTENT_SCRIPT),
429      ActiveScriptTester(
430          kExtensionNames[1],
431          CreateExtension(ALL_HOSTS, EXECUTE_SCRIPT),
432          browser(),
433          DOES_NOT_REQUIRE_CONSENT,
434          EXECUTE_SCRIPT),
435  };
436
437  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
438  ui_test_utils::NavigateToURL(
439      browser(), embedded_test_server()->GetURL("/extensions/test_file.html"));
440
441  for (size_t i = 0u; i < arraysize(testers); ++i)
442    EXPECT_TRUE(testers[i].Verify()) << kExtensionNames[i];
443}
444
445}  // namespace extensions
446