blob: 64dbc1227976cccbaf0d2d55a90f0bf04c3cb58b [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/api/debugger/debugger_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_function_test_utils.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
#include "extensions/browser/extension_function.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/switches.h"
#include "extensions/common/value_builder.h"
namespace extensions {
class DebuggerApiTest : public ExtensionApiTest {
protected:
~DebuggerApiTest() override {}
void SetUpCommandLine(base::CommandLine* command_line) override;
void SetUpOnMainThread() override;
// Run the attach function. If |expected_error| is not empty, then the
// function should fail with the error. Otherwise, the function is expected
// to succeed.
testing::AssertionResult RunAttachFunction(const GURL& url,
const std::string& expected_error);
const Extension* extension() const { return extension_.get(); }
base::CommandLine* command_line() const { return command_line_; }
private:
// The command-line for the test process, preserved in order to modify
// mid-test.
base::CommandLine* command_line_;
// A basic extension with the debugger permission.
scoped_refptr<const Extension> extension_;
};
void DebuggerApiTest::SetUpCommandLine(base::CommandLine* command_line) {
ExtensionApiTest::SetUpCommandLine(command_line);
// We need to hold onto |command_line| in order to modify it during the test.
command_line_ = command_line;
}
void DebuggerApiTest::SetUpOnMainThread() {
ExtensionApiTest::SetUpOnMainThread();
extension_ =
ExtensionBuilder().SetManifest(
DictionaryBuilder().Set("name", "debugger")
.Set("version", "0.1")
.Set("manifest_version", 2)
.Set("permissions",
ListBuilder().Append("debugger"))).Build();
}
testing::AssertionResult DebuggerApiTest::RunAttachFunction(
const GURL& url, const std::string& expected_error) {
ui_test_utils::NavigateToURL(browser(), url);
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
int tab_id = SessionTabHelper::IdForTab(web_contents);
scoped_refptr<DebuggerAttachFunction> attach_function =
new DebuggerAttachFunction();
attach_function->set_extension(extension_.get());
std::string args = base::StringPrintf("[{\"tabId\": %d}, \"1.1\"]", tab_id);
if (!expected_error.empty()) {
std::string actual_error =
extension_function_test_utils::RunFunctionAndReturnError(
attach_function.get(), args, browser());
if (actual_error != expected_error) {
return testing::AssertionFailure() << "Did not get correct error: "
<< "expected: " << expected_error << ", found: " << actual_error;
}
} else {
if (!RunFunction(attach_function.get(),
args,
browser(),
extension_function_test_utils::NONE)) {
return testing::AssertionFailure() << "Could not run function: "
<< attach_function->GetError();
}
// Clean up and detach.
scoped_refptr<DebuggerDetachFunction> detach_function =
new DebuggerDetachFunction();
detach_function->set_extension(extension_.get());
if (!RunFunction(detach_function.get(),
base::StringPrintf("[{\"tabId\": %d}]", tab_id),
browser(),
extension_function_test_utils::NONE)) {
return testing::AssertionFailure() << "Could not detach: "
<< detach_function->GetError();
}
}
return testing::AssertionSuccess();
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Debugger) {
ASSERT_TRUE(RunExtensionTest("debugger")) << message_;
}
IN_PROC_BROWSER_TEST_F(DebuggerApiTest,
DebuggerNotAllowedOnOtherExtensionPages) {
// Load another arbitrary extension with an associated resource (popup.html).
base::FilePath path;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
path = path.AppendASCII("extensions").AppendASCII("good_unpacked");
const Extension* another_extension = LoadExtension(path);
ASSERT_TRUE(another_extension);
GURL other_ext_url =
GURL(base::StringPrintf("chrome-extension://%s/popup.html",
another_extension->id().c_str()));
// This extension should not be able to access another extension.
EXPECT_TRUE(RunAttachFunction(
other_ext_url, manifest_errors::kCannotAccessExtensionUrl));
// This extension *should* be able to debug itself.
EXPECT_TRUE(RunAttachFunction(
GURL(base::StringPrintf("chrome-extension://%s/foo.html",
extension()->id().c_str())),
std::string()));
// Append extensions on chrome urls switch. The extension should now be able
// to debug any extension.
command_line()->AppendSwitch(switches::kExtensionsOnChromeURLs);
EXPECT_TRUE(RunAttachFunction(other_ext_url, std::string()));
}
} // namespace extensions