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 26 namespace extensions { 27 28 class 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 53 void 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 59 void 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 70 testing::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 113 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Debugger) { 114 ASSERT_TRUE(RunExtensionTest("debugger")) << message_; 115 } 116 117 IN_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