Add unit test for crash due to by delayed execution of JS functions on destroyed windows (issue #2038)
This commit is contained in:
parent
cca0bcc8e0
commit
3b499d3d11
|
@ -5,6 +5,7 @@
|
||||||
#include "tests/ceftests/test_handler.h"
|
#include "tests/ceftests/test_handler.h"
|
||||||
|
|
||||||
#include "include/base/cef_bind.h"
|
#include "include/base/cef_bind.h"
|
||||||
|
#include "include/base/cef_logging.h"
|
||||||
#include "include/cef_command_line.h"
|
#include "include/cef_command_line.h"
|
||||||
#include "include/cef_stream.h"
|
#include "include/cef_stream.h"
|
||||||
#include "include/wrapper/cef_closure_task.h"
|
#include "include/wrapper/cef_closure_task.h"
|
||||||
|
@ -283,6 +284,11 @@ CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
|
||||||
|
TerminationStatus status) {
|
||||||
|
LOG(WARNING) << "OnRenderProcessTerminated: status = " << status << ".";
|
||||||
|
}
|
||||||
|
|
||||||
CefRefPtr<CefBrowser> TestHandler::GetBrowser() {
|
CefRefPtr<CefBrowser> TestHandler::GetBrowser() {
|
||||||
return first_browser_;
|
return first_browser_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,6 +182,9 @@ class TestHandler : public CefClient,
|
||||||
CefRefPtr<CefFrame> frame,
|
CefRefPtr<CefFrame> frame,
|
||||||
CefRefPtr<CefRequest> request) override;
|
CefRefPtr<CefRequest> request) override;
|
||||||
|
|
||||||
|
void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
|
||||||
|
TerminationStatus status) override;
|
||||||
|
|
||||||
// These methods should only be used if at most one non-popup browser exists.
|
// These methods should only be used if at most one non-popup browser exists.
|
||||||
CefRefPtr<CefBrowser> GetBrowser();
|
CefRefPtr<CefBrowser> GetBrowser();
|
||||||
int GetBrowserId();
|
int GetBrowserId();
|
||||||
|
|
|
@ -37,6 +37,10 @@ const char kV8ContextEvalCspBypassSandbox[] =
|
||||||
"http://tests/V8Test.ContextEvalCspBypassSandbox";
|
"http://tests/V8Test.ContextEvalCspBypassSandbox";
|
||||||
const char kV8OnUncaughtExceptionTestUrl[] =
|
const char kV8OnUncaughtExceptionTestUrl[] =
|
||||||
"http://tests/V8Test.OnUncaughtException";
|
"http://tests/V8Test.OnUncaughtException";
|
||||||
|
const char kV8HandlerCallOnReleasedContextUrl[] =
|
||||||
|
"http://tests/V8Test.HandlerCallOnReleasedContext/main.html";
|
||||||
|
const char kV8HandlerCallOnReleasedContextChildUrl[] =
|
||||||
|
"http://tests/V8Test.HandlerCallOnReleasedContext/child.html";
|
||||||
const char kV8TestMsg[] = "V8Test.Test";
|
const char kV8TestMsg[] = "V8Test.Test";
|
||||||
const char kV8TestCmdArg[] = "v8-test";
|
const char kV8TestCmdArg[] = "v8-test";
|
||||||
const char kV8RunTestMsg[] = "V8Test.RunTest";
|
const char kV8RunTestMsg[] = "V8Test.RunTest";
|
||||||
|
@ -88,6 +92,7 @@ enum V8TestMode {
|
||||||
V8TEST_ON_UNCAUGHT_EXCEPTION,
|
V8TEST_ON_UNCAUGHT_EXCEPTION,
|
||||||
V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS,
|
V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS,
|
||||||
V8TEST_EXTENSION,
|
V8TEST_EXTENSION,
|
||||||
|
V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set to the current test being run in the browser process. Will always be
|
// Set to the current test being run in the browser process. Will always be
|
||||||
|
@ -254,6 +259,8 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||||
case V8TEST_ON_UNCAUGHT_EXCEPTION:
|
case V8TEST_ON_UNCAUGHT_EXCEPTION:
|
||||||
RunOnUncaughtExceptionTest();
|
RunOnUncaughtExceptionTest();
|
||||||
break;
|
break;
|
||||||
|
case V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// Was a startup test.
|
// Was a startup test.
|
||||||
EXPECT_TRUE(startup_test_success_);
|
EXPECT_TRUE(startup_test_success_);
|
||||||
|
@ -2482,6 +2489,79 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
|
||||||
EXPECT_TRUE(object.get());
|
EXPECT_TRUE(object.get());
|
||||||
EXPECT_TRUE(object->SetValue("v8_binding_test", CefV8Value::CreateInt(12),
|
EXPECT_TRUE(object->SetValue("v8_binding_test", CefV8Value::CreateInt(12),
|
||||||
V8_PROPERTY_ATTRIBUTE_NONE));
|
V8_PROPERTY_ATTRIBUTE_NONE));
|
||||||
|
} else if (url == kV8HandlerCallOnReleasedContextUrl) {
|
||||||
|
// For V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT
|
||||||
|
class Handler : public CefV8Handler {
|
||||||
|
public:
|
||||||
|
Handler(CefRefPtr<V8RendererTest> renderer_test)
|
||||||
|
: renderer_test_(renderer_test) {}
|
||||||
|
|
||||||
|
bool Execute(const CefString& name,
|
||||||
|
CefRefPtr<CefV8Value> object,
|
||||||
|
const CefV8ValueList& arguments,
|
||||||
|
CefRefPtr<CefV8Value>& retval,
|
||||||
|
CefString& exception) override {
|
||||||
|
if (name == "notify_test_done") {
|
||||||
|
CefPostDelayedTask(
|
||||||
|
TID_RENDERER,
|
||||||
|
base::Bind(&V8RendererTest::DestroyTest, renderer_test_.get()),
|
||||||
|
1000);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CefRefPtr<V8RendererTest> renderer_test_;
|
||||||
|
IMPLEMENT_REFCOUNTING(Handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
Handler* handler = new Handler(this);
|
||||||
|
CefRefPtr<CefV8Handler> handlerPtr(handler);
|
||||||
|
|
||||||
|
// Function that will be called from the parent frame context.
|
||||||
|
CefRefPtr<CefV8Value> func =
|
||||||
|
CefV8Value::CreateFunction("notify_test_done", handler);
|
||||||
|
EXPECT_TRUE(func.get());
|
||||||
|
|
||||||
|
CefRefPtr<CefV8Value> object = context->GetGlobal();
|
||||||
|
EXPECT_TRUE(object.get());
|
||||||
|
EXPECT_TRUE(object->SetValue("notify_test_done", func,
|
||||||
|
V8_PROPERTY_ATTRIBUTE_NONE));
|
||||||
|
} else if (url == kV8HandlerCallOnReleasedContextChildUrl) {
|
||||||
|
// For V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT
|
||||||
|
class Handler : public CefV8Handler {
|
||||||
|
public:
|
||||||
|
Handler() {}
|
||||||
|
bool Execute(const CefString& name,
|
||||||
|
CefRefPtr<CefV8Value> object,
|
||||||
|
const CefV8ValueList& arguments,
|
||||||
|
CefRefPtr<CefV8Value>& retval,
|
||||||
|
CefString& exception) override {
|
||||||
|
if (name == "v8_context_is_alive") {
|
||||||
|
retval = CefV8Value::CreateBool(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMPLEMENT_REFCOUNTING(Handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
Handler* handler = new Handler;
|
||||||
|
CefRefPtr<CefV8Handler> handlerPtr(handler);
|
||||||
|
|
||||||
|
// Function that will be called from the parent frame context.
|
||||||
|
CefRefPtr<CefV8Value> func =
|
||||||
|
CefV8Value::CreateFunction("v8_context_is_alive", handler);
|
||||||
|
EXPECT_TRUE(func.get());
|
||||||
|
|
||||||
|
CefRefPtr<CefV8Value> object = context->GetGlobal();
|
||||||
|
EXPECT_TRUE(object.get());
|
||||||
|
EXPECT_TRUE(object->SetValue("v8_context_is_alive", func,
|
||||||
|
V8_PROPERTY_ATTRIBUTE_NONE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2714,6 +2794,58 @@ class V8TestHandler : public TestHandler {
|
||||||
"</body></html>\n",
|
"</body></html>\n",
|
||||||
"text/html");
|
"text/html");
|
||||||
CreateBrowser(kV8OnUncaughtExceptionTestUrl);
|
CreateBrowser(kV8OnUncaughtExceptionTestUrl);
|
||||||
|
} else if (test_mode_ == V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT) {
|
||||||
|
AddResource(kV8HandlerCallOnReleasedContextUrl,
|
||||||
|
"<html><body onload='createFrame()'>"
|
||||||
|
"(main)"
|
||||||
|
"<script>"
|
||||||
|
"function createFrame() {"
|
||||||
|
" var el = document.createElement('iframe');"
|
||||||
|
" el.id = 'child';"
|
||||||
|
" el.src = '" +
|
||||||
|
std::string(kV8HandlerCallOnReleasedContextChildUrl) +
|
||||||
|
"';"
|
||||||
|
" el.onload = function() {"
|
||||||
|
" setTimeout(function() {"
|
||||||
|
" try {"
|
||||||
|
" el.contentWindow.removeMe();"
|
||||||
|
" window.notify_test_done();"
|
||||||
|
" } catch (e) { alert('Unit test error.\\n' + e); }"
|
||||||
|
" }, 1000);"
|
||||||
|
" };"
|
||||||
|
" document.body.appendChild(el);"
|
||||||
|
"}"
|
||||||
|
""
|
||||||
|
"function removeFrame(id) {"
|
||||||
|
" var el = document.getElementById(id);"
|
||||||
|
" if (el) { el.parentElement.removeChild(el); }"
|
||||||
|
" else { alert('Error in test. No element \"' + id + "
|
||||||
|
"'\" found.'); }"
|
||||||
|
"}"
|
||||||
|
"</script>"
|
||||||
|
"</body></html>",
|
||||||
|
"text/html");
|
||||||
|
AddResource(kV8HandlerCallOnReleasedContextChildUrl,
|
||||||
|
"<html><body>"
|
||||||
|
"(child)"
|
||||||
|
"<script>"
|
||||||
|
"try {"
|
||||||
|
" if (!window.v8_context_is_alive()) {"
|
||||||
|
" throw 'v8_context_is_alive returns non-true value.';"
|
||||||
|
" }"
|
||||||
|
"} catch (e) {"
|
||||||
|
" alert('Unit test error.\\n' + e);"
|
||||||
|
"}"
|
||||||
|
""
|
||||||
|
"function removeMe() {"
|
||||||
|
" var w = window;"
|
||||||
|
" w.parent.removeFrame('child');"
|
||||||
|
" return w.v8_context_is_alive();"
|
||||||
|
"}"
|
||||||
|
"</script>"
|
||||||
|
"</body></html>",
|
||||||
|
"text/html");
|
||||||
|
CreateBrowser(kV8HandlerCallOnReleasedContextUrl);
|
||||||
} else {
|
} else {
|
||||||
EXPECT_TRUE(test_url_ != NULL);
|
EXPECT_TRUE(test_url_ != NULL);
|
||||||
AddResource(test_url_,
|
AddResource(test_url_,
|
||||||
|
@ -2879,3 +3011,6 @@ V8_TEST(StackTrace, V8TEST_STACK_TRACE);
|
||||||
V8_TEST(OnUncaughtException, V8TEST_ON_UNCAUGHT_EXCEPTION);
|
V8_TEST(OnUncaughtException, V8TEST_ON_UNCAUGHT_EXCEPTION);
|
||||||
V8_TEST(OnUncaughtExceptionDevTools, V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS);
|
V8_TEST(OnUncaughtExceptionDevTools, V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS);
|
||||||
V8_TEST(Extension, V8TEST_EXTENSION);
|
V8_TEST(Extension, V8TEST_EXTENSION);
|
||||||
|
V8_TEST_EX(HandlerCallOnReleasedContext,
|
||||||
|
V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT,
|
||||||
|
kV8HandlerCallOnReleasedContextUrl)
|
||||||
|
|
Loading…
Reference in New Issue