0

Expand RuntimeErrors for ErrorConsole

Include two of our internal scripts (event_bindings and schemaUtil) as sources
for runtime errors.  Add tests for same.

BUG=21734

Review URL: https://chromiumcodereview.appspot.com/23923003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221652 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
rdevlin.cronin@chromium.org
2013-09-06 08:41:07 +00:00
parent 28c3d0a9c7
commit a0ed268cd5
15 changed files with 150 additions and 21 deletions
chrome
browser
renderer
test
data
extensions
error_console
bad_api_arguments_runtime_error
bad_api_permissions_runtime_error
extensions

@ -20,6 +20,7 @@
#include "extensions/browser/extension_error.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension_urls.h"
#include "extensions/common/manifest_constants.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -420,7 +421,6 @@ IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, BrowserActionRuntimeError) {
ACTION_BROWSER_ACTION,
&extension);
std::string event_bindings_str = "event_bindings";
std::string script_url = extension->url().Resolve("browser_action.js").spec();
const ErrorConsole::ErrorList& errors =
@ -444,10 +444,77 @@ IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, BrowserActionRuntimeError) {
"extensions::SafeBuiltins",
std::string("Function.target.") + kAnonymousFunction);
CheckStackFrame(
stack_trace[2], event_bindings_str, "Event.dispatchToListener");
CheckStackFrame(stack_trace[3], event_bindings_str, "Event.dispatch_");
CheckStackFrame(stack_trace[4], event_bindings_str, "dispatchArgs");
CheckStackFrame(stack_trace[5], event_bindings_str, "dispatchEvent");
stack_trace[2], kEventBindings, "Event.dispatchToListener");
CheckStackFrame(stack_trace[3], kEventBindings, "Event.dispatch_");
CheckStackFrame(stack_trace[4], kEventBindings, "dispatchArgs");
CheckStackFrame(stack_trace[5], kEventBindings, "dispatchEvent");
}
// Test that we can catch an error for calling an API with improper arguments.
IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, BadAPIArgumentsRuntimeError) {
const Extension* extension = NULL;
LoadExtensionAndCheckErrors(
"bad_api_arguments_runtime_error",
kNoFlags,
1, // One error: call an API with improper arguments.
ACTION_NONE,
&extension);
const ErrorConsole::ErrorList& errors =
error_console()->GetErrorsForExtension(extension->id());
CheckRuntimeError(
errors[0],
extension->id(),
kSchemaUtils, // API calls are checked in schemaUtils.js.
false, // not incognito
"Uncaught Error: Invocation of form "
"tabs.get(string, function) doesn't match definition "
"tabs.get(integer tabId, function callback)",
logging::LOG_ERROR,
extension->url().Resolve(kBackgroundPageName),
1u);
const StackTrace& stack_trace = GetStackTraceFromError(errors[0]);
ASSERT_EQ(1u, stack_trace.size());
CheckStackFrame(stack_trace[0],
kSchemaUtils,
kAnonymousFunction);
}
// Test that we catch an error when we try to call an API method without
// permission.
IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, BadAPIPermissionsRuntimeError) {
const Extension* extension = NULL;
LoadExtensionAndCheckErrors(
"bad_api_permissions_runtime_error",
kNoFlags,
1, // One error: we try to call addUrl() on chrome.history without
// permission, which results in a TypeError.
ACTION_NONE,
&extension);
std::string script_url = extension->url().Resolve("background.js").spec();
const ErrorConsole::ErrorList& errors =
error_console()->GetErrorsForExtension(extension->id());
CheckRuntimeError(
errors[0],
extension->id(),
script_url,
false, // not incognito
"Uncaught TypeError: Cannot call method 'addUrl' of undefined",
logging::LOG_ERROR,
extension->url().Resolve(kBackgroundPageName),
1u);
const StackTrace& stack_trace = GetStackTraceFromError(errors[0]);
ASSERT_EQ(1u, stack_trace.size());
CheckStackFrame(stack_trace[0],
script_url,
kAnonymousFunction,
5u, 1u);
}
} // namespace extensions

@ -51,6 +51,7 @@ scoped_ptr<ExtensionError> CreateNewRuntimeError(
const std::string& extension_id,
const string16& message) {
return scoped_ptr<ExtensionError>(new RuntimeError(
extension_id,
from_incognito,
GetSourceForExtensionId(extension_id),
message,

@ -36,6 +36,7 @@
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_process_host.h"
#include "extensions/common/extension_urls.h"
using base::DictionaryValue;
using base::ListValue;
@ -134,7 +135,7 @@ void EventRouter::DispatchExtensionMessage(IPC::Sender* ipc_sender,
ipc_sender->Send(new ExtensionMsg_MessageInvoke(
MSG_ROUTING_CONTROL,
extension_id,
"event_bindings",
kEventBindings,
"dispatchEvent",
args,
user_gesture == USER_GESTURE_ENABLED));

@ -586,15 +586,20 @@ void ExtensionHost::OnDetailedConsoleMessageAdded(
const StackTrace& stack_trace,
int32 severity_level) {
if (IsSourceFromAnExtension(source)) {
GURL context_url;
if (associated_web_contents_)
context_url = associated_web_contents_->GetLastCommittedURL();
else if (host_contents_.get())
context_url = host_contents_->GetLastCommittedURL();
ErrorConsole::Get(profile_)->ReportError(
scoped_ptr<ExtensionError>(new RuntimeError(
extension_id_,
profile_->IsOffTheRecord(),
source,
message,
stack_trace,
associated_web_contents_ ?
associated_web_contents_->GetLastCommittedURL() :
GURL::EmptyGURL(),
context_url,
static_cast<logging::LogSeverity>(severity_level))));
}
}

@ -5,6 +5,7 @@
#include "chrome/browser/extensions/tab_helper.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/activity_log/activity_log.h"
#include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
@ -364,6 +365,7 @@ void TabHelper::OnDetailedConsoleMessageAdded(
if (IsSourceFromAnExtension(source)) {
ErrorConsole::Get(profile_)->ReportError(
scoped_ptr<ExtensionError>(new RuntimeError(
extension_app_ ? extension_app_->id() : EmptyString(),
profile_->IsOffTheRecord(),
source,
message,

@ -78,6 +78,7 @@
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/v8_value_converter.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension_urls.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_provider.h"
#include "extensions/common/manifest.h"
@ -118,7 +119,6 @@ namespace {
static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
static const char kEventModule[] = "event_bindings";
static const char kEventDispatchFunction[] = "dispatchEvent";
// Returns the global value for "chrome" from |context|. If one doesn't exist
@ -905,12 +905,12 @@ void Dispatcher::PopulateSourceMap() {
// Libraries.
source_map_.RegisterSource("contentWatcher", IDR_CONTENT_WATCHER_JS);
source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER);
source_map_.RegisterSource(kEventModule, IDR_EVENT_BINDINGS_JS);
source_map_.RegisterSource(kEventBindings, IDR_EVENT_BINDINGS_JS);
source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS);
source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS);
source_map_.RegisterSource("messaging", IDR_MESSAGING_JS);
source_map_.RegisterSource("schemaUtils", IDR_SCHEMA_UTILS_JS);
source_map_.RegisterSource(kSchemaUtils, IDR_SCHEMA_UTILS_JS);
source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS);
source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS);
source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS);
@ -1091,7 +1091,7 @@ void Dispatcher::DidCreateScriptContext(
if (context->extension()) {
v8::Handle<v8::Object> chrome = AsObjectOrEmpty(GetOrCreateChrome(context));
if (!chrome.IsEmpty())
module_system->SetLazyField(chrome, "Event", kEventModule, "Event");
module_system->SetLazyField(chrome, "Event", kEventBindings, "Event");
}
AddOrRemoveBindingsForContext(context);
@ -1521,11 +1521,14 @@ void Dispatcher::DispatchEvent(const std::string& extension_id,
base::ListValue args;
args.Set(0, new base::StringValue(event_name));
args.Set(1, new base::ListValue());
// Needed for Windows compilation, since kEventBindings is declared extern.
const char* local_event_bindings = kEventBindings;
v8_context_set_.ForEach(
extension_id,
NULL, // all render views
base::Bind(&CallModuleMethod,
kEventModule,
local_event_bindings,
kEventDispatchFunction,
&args));
}
@ -1557,7 +1560,7 @@ void Dispatcher::InvokeModuleSystemMethod(
// background page active.
const Extension* extension = extensions_.GetByID(extension_id);
if (extension && BackgroundInfo::HasLazyBackgroundPage(extension) &&
module_name == kEventModule &&
module_name == kEventBindings &&
function_name == kEventDispatchFunction) {
RenderView* background_view =
ExtensionHelper::GetBackgroundPage(extension_id);

@ -4,6 +4,7 @@
#include "chrome/test/base/module_system_test.h"
#include "extensions/common/extension_urls.h"
#include "grit/renderer_resources.h"
namespace extensions {
@ -13,9 +14,9 @@ class EventUnittest : public ModuleSystemTest {
virtual void SetUp() OVERRIDE {
ModuleSystemTest::SetUp();
RegisterModule("event_bindings", IDR_EVENT_BINDINGS_JS);
RegisterModule(kEventBindings, IDR_EVENT_BINDINGS_JS);
RegisterModule("json_schema", IDR_JSON_SCHEMA_JS);
RegisterModule("schemaUtils", IDR_SCHEMA_UTILS_JS);
RegisterModule(kSchemaUtils, IDR_SCHEMA_UTILS_JS);
RegisterModule("unload_event", IDR_UNLOAD_EVENT_JS);
RegisterModule("utils", IDR_UTILS_JS);

@ -0,0 +1,5 @@
// Copyright 2013 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.
chrome.tabs.get("ThisShouldBeAnInteger", function(tab) { });

@ -0,0 +1,12 @@
{
"name": "Bad API Arguments Runtime Error",
"description": "Try to call an API (tabs) with improper arguments, causing a runtime error.",
"version": "1.0",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"permissions": [
"tabs", "*://*/*"
]
}

@ -0,0 +1,5 @@
// Copyright 2013 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.
chrome.history.addUrl({"url": "https://www.google.com/"});

@ -0,0 +1,12 @@
{
"name": "Bad API Permissions Runtime Error",
"description": "Try to call an API without permission, causing a runtime error.",
"version": "1.0",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"permissions": [
"tabs", "*://*/*"
]
}

@ -120,14 +120,15 @@ bool ManifestError::IsEqualImpl(const ExtensionError* rhs) const {
return true;
}
RuntimeError::RuntimeError(bool from_incognito,
RuntimeError::RuntimeError(const std::string& extension_id,
bool from_incognito,
const string16& source,
const string16& message,
const StackTrace& stack_trace,
const GURL& context_url,
logging::LogSeverity level)
: ExtensionError(ExtensionError::RUNTIME_ERROR,
GURL(source).host(),
!extension_id.empty() ? extension_id : GURL(source).host(),
from_incognito,
level,
source,

@ -120,7 +120,8 @@ class ManifestError : public ExtensionError {
class RuntimeError : public ExtensionError {
public:
RuntimeError(bool from_incognito,
RuntimeError(const std::string& extension_id, // optional, sometimes unknown.
bool from_incognito,
const base::string16& source,
const base::string16& message,
const StackTrace& stack_trace,

@ -4,13 +4,20 @@
#include "extensions/common/extension_urls.h"
#include "base/strings/utf_string_conversions.h"
#include "extensions/common/constants.h"
#include "url/gurl.h"
namespace extensions {
const char kEventBindings[] = "event_bindings";
const char kSchemaUtils[] = "schemaUtils";
bool IsSourceFromAnExtension(const base::string16& source) {
return GURL(source).SchemeIs(kExtensionScheme);
return GURL(source).SchemeIs(kExtensionScheme) ||
source == base::UTF8ToUTF16(kEventBindings) ||
source == base::UTF8ToUTF16(kSchemaUtils);
}
} // namespace extensions

@ -9,6 +9,12 @@
namespace extensions {
// The name of the event_bindings module.
extern const char kEventBindings[];
// The name of the schemaUtils module.
extern const char kSchemaUtils[];
// Determine whether or not a source came from an extension. |source| can link
// to a page or a script, and can be external (e.g., "http://www.google.com"),
// extension-related (e.g., "chrome-extension://<extension_id>/background.js"),