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 <string> 6 7#include "base/command_line.h" 8#include "base/memory/ref_counted.h" 9#include "base/path_service.h" 10#include "base/strings/stringprintf.h" 11#include "chrome/browser/extensions/api/debugger/debugger_api.h" 12#include "chrome/browser/extensions/extension_apitest.h" 13#include "chrome/browser/extensions/extension_function_test_utils.h" 14#include "chrome/browser/ui/tabs/tab_strip_model.h" 15#include "chrome/common/chrome_paths.h" 16#include "chrome/common/chrome_switches.h" 17#include "chrome/test/base/ui_test_utils.h" 18#include "extensions/browser/extension_function.h" 19#include "extensions/common/extension.h" 20#include "extensions/common/extension_builder.h" 21#include "extensions/common/manifest_constants.h" 22#include "extensions/common/switches.h" 23#include "extensions/common/value_builder.h" 24 25namespace extensions { 26 27class DebuggerApiTest : public ExtensionApiTest { 28 protected: 29 virtual ~DebuggerApiTest() {} 30 31 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE; 32 virtual void SetUpOnMainThread() OVERRIDE; 33 34 // Run the attach function. If |expected_error| is not empty, then the 35 // function should fail with the error. Otherwise, the function is expected 36 // to succeed. 37 testing::AssertionResult RunAttachFunction(const GURL& url, 38 const std::string& expected_error); 39 40 const Extension* extension() const { return extension_; } 41 base::CommandLine* command_line() const { return command_line_; } 42 43 private: 44 // The command-line for the test process, preserved in order to modify 45 // mid-test. 46 base::CommandLine* command_line_; 47 48 // A basic extension with the debugger permission. 49 scoped_refptr<const Extension> extension_; 50}; 51 52void DebuggerApiTest::SetUpCommandLine(base::CommandLine* command_line) { 53 ExtensionApiTest::SetUpCommandLine(command_line); 54 // We need to hold onto |command_line| in order to modify it during the test. 55 command_line_ = command_line; 56} 57 58void DebuggerApiTest::SetUpOnMainThread() { 59 ExtensionApiTest::SetUpOnMainThread(); 60 extension_ = 61 ExtensionBuilder().SetManifest( 62 DictionaryBuilder().Set("name", "debugger") 63 .Set("version", "0.1") 64 .Set("manifest_version", 2) 65 .Set("permissions", 66 ListBuilder().Append("debugger"))).Build(); 67} 68 69testing::AssertionResult DebuggerApiTest::RunAttachFunction( 70 const GURL& url, const std::string& expected_error) { 71 ui_test_utils::NavigateToURL(browser(), url); 72 content::WebContents* web_contents = 73 browser()->tab_strip_model()->GetActiveWebContents(); 74 int tab_id = SessionID::IdForTab(web_contents); 75 scoped_refptr<DebuggerAttachFunction> attach_function = 76 new DebuggerAttachFunction(); 77 attach_function->set_extension(extension_); 78 std::string args = base::StringPrintf("[{\"tabId\": %d}, \"1.1\"]", tab_id); 79 80 if (!expected_error.empty()) { 81 std::string actual_error = 82 extension_function_test_utils::RunFunctionAndReturnError( 83 attach_function, args, browser()); 84 if (actual_error != expected_error) { 85 return testing::AssertionFailure() << "Did not get correct error: " 86 << "expected: " << expected_error << ", found: " << actual_error; 87 } 88 } else { 89 if (!RunFunction(attach_function, 90 args, 91 browser(), 92 extension_function_test_utils::NONE)) { 93 return testing::AssertionFailure() << "Could not run function: " 94 << attach_function->GetError(); 95 } 96 97 // Clean up and detach. 98 scoped_refptr<DebuggerDetachFunction> detach_function = 99 new DebuggerDetachFunction(); 100 detach_function->set_extension(extension_); 101 if (!RunFunction(detach_function, 102 base::StringPrintf("[{\"tabId\": %d}]", tab_id), 103 browser(), 104 extension_function_test_utils::NONE)) { 105 return testing::AssertionFailure() << "Could not detach: " 106 << detach_function->GetError(); 107 } 108 } 109 return testing::AssertionSuccess(); 110} 111 112IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Debugger) { 113 ASSERT_TRUE(RunExtensionTest("debugger")) << message_; 114} 115 116IN_PROC_BROWSER_TEST_F(DebuggerApiTest, 117 DebuggerNotAllowedOnOtherExtensionPages) { 118 // Load another arbitrary extension with an associated resource (popup.html). 119 base::FilePath path; 120 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path)); 121 path = path.AppendASCII("extensions").AppendASCII("good_unpacked"); 122 const Extension* another_extension = LoadExtension(path); 123 ASSERT_TRUE(another_extension); 124 125 GURL other_ext_url = 126 GURL(base::StringPrintf("chrome-extension://%s/popup.html", 127 another_extension->id().c_str())); 128 129 // This extension should not be able to access another extension. 130 EXPECT_TRUE(RunAttachFunction( 131 other_ext_url, manifest_errors::kCannotAccessExtensionUrl)); 132 133 // This extension *should* be able to debug itself. 134 EXPECT_TRUE(RunAttachFunction( 135 GURL(base::StringPrintf("chrome-extension://%s/foo.html", 136 extension()->id().c_str())), 137 std::string())); 138 139 // Append extensions on chrome urls switch. The extension should now be able 140 // to debug any extension. 141 command_line()->AppendSwitch(switches::kExtensionsOnChromeURLs); 142 EXPECT_TRUE(RunAttachFunction(other_ext_url, std::string())); 143} 144 145} // namespace extensions 146