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