diff options
author | wez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-06 17:48:25 +0000 |
---|---|---|
committer | wez@chromium.org <wez@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-09-06 17:48:25 +0000 |
commit | 0c2a2f543db364b6575a58ce7f3b9da1ad38c7ac (patch) | |
tree | fe4f0b725ddd687c168f9d01ad80f2d4987eb344 | |
parent | e4939783eecea0c43eed8b46b8347dcaf9bd03a2 (diff) | |
download | chromium_src-0c2a2f543db364b6575a58ce7f3b9da1ad38c7ac.zip chromium_src-0c2a2f543db364b6575a58ce7f3b9da1ad38c7ac.tar.gz chromium_src-0c2a2f543db364b6575a58ce7f3b9da1ad38c7ac.tar.bz2 |
Add DeletePluginInDeallocate UI test.
BUG=94179
TEST=
Review URL: http://codereview.chromium.org/7806020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99762 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/test/data/npapi/plugin_delete_in_deallocate.html | 55 | ||||
-rw-r--r-- | chrome/test/ui/npapi_test_helper.cc | 3 | ||||
-rw-r--r-- | chrome/test/ui/npapi_uitest.cc | 16 | ||||
-rw-r--r-- | webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.cc | 151 | ||||
-rw-r--r-- | webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.h | 30 | ||||
-rw-r--r-- | webkit/plugins/npapi/test/plugin_test_factory.cc | 5 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.gypi | 2 |
7 files changed, 259 insertions, 3 deletions
diff --git a/chrome/test/data/npapi/plugin_delete_in_deallocate.html b/chrome/test/data/npapi/plugin_delete_in_deallocate.html new file mode 100644 index 0000000..4904469 --- /dev/null +++ b/chrome/test/data/npapi/plugin_delete_in_deallocate.html @@ -0,0 +1,55 @@ +<html> +<head> +<script src="npapi.js"></script> +<script> +function setTestObject(object) { + window.testObject = object; + setTimeout("deleteTestObject()", 0); + var statusPanel = document.getElementById("statusPanel"); + statusPanel.innerText = "Received test object..."; +} + +function deleteTestObject() { + window.testObject = null; + var statusPanel = document.getElementById("statusPanel"); + statusPanel.innerText = "Deleted test object..."; + gc(); +} + +function deletePlugin() { + var statusPanel = document.getElementById("statusPanel"); + statusPanel.innerText = "Deleting plugin..."; + var plugin = document.getElementById("delete_plugin_in_deallocate_test"); + if (plugin.parentNode && plugin.parentNode.removeChild) { + plugin.parentNode.removeChild(plugin); + } +} +</script> +</head> + +<body> +<div id="statusPanel" style="border: 1px solid red; width: 100%"> +Test running.... +</div> + +NPObject Delete in Deallocate<p> + +Tests the case where deallocation of an NPObject belonging to the plugin +triggers scripting which causes the whole plugin to be torn down, and verifies +that the object being deallocated is not deallocated a second time. + + +<embed type="application/vnd.npapi-test" + src="foo" + name="delete_plugin_in_deallocate_test" + id="signaller" + mode="np_embed"> + +<embed type="application/vnd.npapi-test" + src="foo" + name="delete_plugin_in_deallocate_test" + id="delete_plugin_in_deallocate_test" + mode="np_embed"> + +</body> +</html> diff --git a/chrome/test/ui/npapi_test_helper.cc b/chrome/test/ui/npapi_test_helper.cc index 65bf5a7..a376656 100644 --- a/chrome/test/ui/npapi_test_helper.cc +++ b/chrome/test/ui/npapi_test_helper.cc @@ -16,6 +16,9 @@ const char kTestCompleteSuccess[] = "OK"; } // namespace npapi_test. NPAPITesterBase::NPAPITesterBase() { + // Some NPAPI tests schedule garbage collection to force object tear-down. + launch_arguments_.AppendSwitchASCII(switches::kJavaScriptFlags, + "--expose_gc"); } void NPAPITesterBase::SetUp() { diff --git a/chrome/test/ui/npapi_uitest.cc b/chrome/test/ui/npapi_uitest.cc index 2ebf2b6..577ac59 100644 --- a/chrome/test/ui/npapi_uitest.cc +++ b/chrome/test/ui/npapi_uitest.cc @@ -29,14 +29,15 @@ #include "chrome/test/base/ui_test_utils.h" #include "chrome/test/ui/npapi_test_helper.h" #include "content/browser/net/url_request_mock_http_job.h" +#include "content/common/content_switches.h" using npapi_test::kTestCompleteCookie; using npapi_test::kTestCompleteSuccess; -static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("npapi"); - namespace { +const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("npapi"); + class NPAPIAutomationEnabledTest : public NPAPIVisiblePluginTester { public: NPAPIAutomationEnabledTest() { @@ -159,6 +160,17 @@ TEST_F(NPAPIVisiblePluginTester, SelfDeletePluginInNewStream) { TestTimeouts::action_max_timeout_ms()); } +TEST_F(NPAPIVisiblePluginTester, DeletePluginInDeallocate) { + show_window_ = true; + const FilePath test_case( + FILE_PATH_LITERAL("plugin_delete_in_deallocate.html")); + GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case); + ASSERT_NO_FATAL_FAILURE(NavigateToURL(url)); + WaitForFinish("delete_plugin_in_deallocate_test", "signaller", url, + kTestCompleteCookie, kTestCompleteSuccess, + TestTimeouts::action_max_timeout_ms()); +} + #if defined(OS_WIN) // Tests if a plugin has a non zero window rect. TEST_F(NPAPIVisiblePluginTester, VerifyPluginWindowRect) { diff --git a/webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.cc b/webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.cc new file mode 100644 index 0000000..a1053be --- /dev/null +++ b/webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.cc @@ -0,0 +1,151 @@ +// Copyright (c) 2011 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 "webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.h" + +#include "base/basictypes.h" +#include "base/compiler_specific.h" + +namespace { + +NPAPIClient::DeletePluginInDeallocateTest* g_signalling_instance_ = NULL; + +class DeletePluginInDeallocateTestNPObject : public NPObject { + public: + DeletePluginInDeallocateTestNPObject() + : NPObject(), id_(NULL), host_functions_(NULL), deallocate_count_(0) {} + + static NPObject* Allocate(NPP npp, NPClass* npclass) { + return new DeletePluginInDeallocateTestNPObject(); + } + + static void Deallocate(NPObject* npobject) { + DeletePluginInDeallocateTestNPObject* object = + reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject); + ++object->deallocate_count_; + + // Call window.deletePlugin to tear-down our plugin from inside deallocate. + if (object->deallocate_count_ == 1) { + NPIdentifier delete_id = + object->host_functions_->getstringidentifier("deletePlugin"); + NPObject* window_obj = NULL; + object->host_functions_->getvalue(object->id_, NPNVWindowNPObject, + &window_obj); + NPVariant rv; + object->host_functions_->invoke(object->id_, window_obj, delete_id, NULL, + 0, &rv); + } + } + + NPP id_; + NPNetscapeFuncs* host_functions_; + int deallocate_count_; +}; + +NPClass* GetDeletePluginInDeallocateTestClass() { + static NPClass plugin_class = { + NP_CLASS_STRUCT_VERSION, + DeletePluginInDeallocateTestNPObject::Allocate, + DeletePluginInDeallocateTestNPObject::Deallocate, + NULL, // Invalidate + NULL, // HasMethod + NULL, // Invoke + NULL, // InvokeDefault + NULL, // HasProperty + NULL, // GetProperty + NULL, // SetProperty + NULL, // RemoveProperty + }; + return &plugin_class; +} + +} // namespace + +namespace NPAPIClient { + +DeletePluginInDeallocateTest::DeletePluginInDeallocateTest( + NPP id, NPNetscapeFuncs* host_functions) + : PluginTest(id, host_functions), npobject_(NULL), test_started_(false) { +} + +NPError DeletePluginInDeallocateTest::SetWindow(NPWindow* pNPWindow) { + if (pNPWindow->window == NULL) + return NPERR_NO_ERROR; + + // Ensure that we run the test once, even if SetWindow is called again. + if (test_started_) + return NPERR_NO_ERROR; + test_started_ = true; + + // Because of http://crbug.com/94829, we have to have a second plugin + // instance that we can use to signal completion. + if (test_id() == "signaller") { + g_signalling_instance_ = this; + return NPERR_NO_ERROR; + } + + // Create a custom NPObject and give our Id and the Netscape function table. + npobject_ = HostFunctions()->createobject( + id(), GetDeletePluginInDeallocateTestClass()); + DeletePluginInDeallocateTestNPObject* test_object = + reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject_); + test_object->id_ = id(); + test_object->host_functions_ = HostFunctions(); + + // Fetch the window script object for our page. + NPObject* window = NULL; + HostFunctions()->getvalue(id(), NPNVWindowNPObject, &window); + + // Pass it to the window.setTestObject function, which will later release it. + NPIdentifier set_test_object_id = + HostFunctions()->getstringidentifier("setTestObject"); + NPVariant func_var; + NULL_TO_NPVARIANT(func_var); + HostFunctions()->getproperty(id(), window, set_test_object_id, &func_var); + + NPObject* func = NPVARIANT_TO_OBJECT(func_var); + NPVariant func_arg; + OBJECT_TO_NPVARIANT(npobject_, func_arg); + NPVariant func_result; + HostFunctions()->invokeDefault(id(), func, &func_arg, 1, + &func_result); + + // Release the object - the page's reference should keep it alive. + HostFunctions()->releaseobject(npobject_); + + return NPERR_NO_ERROR; +} + +NPError DeletePluginInDeallocateTest::Destroy() { + // Because of http://crbug.com/94829, we can't signal completion from within + // the NPP_Destroy of the plugin that is being destroyed. We work-around + // that by testing using a second instance, and signalling though the main + // test instance. + + // There should always be a signalling instance by the time we reach here. + if (!g_signalling_instance_) + return NPERR_NO_ERROR; + + // If we're the signalling instance, do nothing. + if (g_signalling_instance_ == this) + return NPERR_NO_ERROR; + + if (!npobject_) { + g_signalling_instance_->SetError("SetWindow was not invoked."); + } else { + // Verify that our object was deallocated exactly once. + DeletePluginInDeallocateTestNPObject* test_object = + reinterpret_cast<DeletePluginInDeallocateTestNPObject*>(npobject_); + if (test_object->deallocate_count_ != 1) + g_signalling_instance_->SetError( + "Object was not deallocated exactly once."); + delete test_object; + } + + g_signalling_instance_->SignalTestCompleted(); + + return NPERR_NO_ERROR; +} + +} // namespace NPAPIClient diff --git a/webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.h b/webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.h new file mode 100644 index 0000000..4dabd0e --- /dev/null +++ b/webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.h @@ -0,0 +1,30 @@ +// Copyright (c) 2011 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. +#ifndef WEBKIT_PLUGINS_NPAPI_TEST_DELETE_PLUGIN_IN_DEALLOCATE_TEST_H_ +#define WEBKIT_PLUGINS_NPAPI_TEST_DELETE_PLUGIN_IN_DEALLOCATE_TEST_H_ + +#include "webkit/plugins/npapi/test/plugin_test.h" + +namespace NPAPIClient { + +// This test verifies that if a plugin scripts the page from within an +// NPObject's deallocation, and the page tears down the plugin, then that +// object doesn't end up being double-freed. + +class DeletePluginInDeallocateTest : public PluginTest { + public: + // Constructor. + DeletePluginInDeallocateTest(NPP id, NPNetscapeFuncs* host_functions); + + // NPAPI handlers. + virtual NPError SetWindow(NPWindow* pNPWindow); + virtual NPError Destroy(); + + NPObject* npobject_; + bool test_started_; +}; + +} // namespace NPAPIClient + +#endif // WEBKIT_PLUGINS_NPAPI_TEST_DELETE_PLUGIN_IN_DEALLOCATE_TEST_H_ diff --git a/webkit/plugins/npapi/test/plugin_test_factory.cc b/webkit/plugins/npapi/test/plugin_test_factory.cc index 4fe7689..a1931f2 100644 --- a/webkit/plugins/npapi/test/plugin_test_factory.cc +++ b/webkit/plugins/npapi/test/plugin_test_factory.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -6,6 +6,7 @@ #include "webkit/plugins/npapi/test/plugin_arguments_test.h" #include "webkit/plugins/npapi/test/plugin_delete_plugin_in_stream_test.h" +#include "webkit/plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.h" #include "webkit/plugins/npapi/test/plugin_get_javascript_url_test.h" #include "webkit/plugins/npapi/test/plugin_get_javascript_url2_test.h" #include "webkit/plugins/npapi/test/plugin_geturl_test.h" @@ -99,6 +100,8 @@ PluginTest* CreatePluginTest(const std::string& test_name, } else if (test_name == "setup") { // "plugin" is the name for plugin documents. new_test = new PluginSetupTest(instance, host_functions); + } else if (test_name == "delete_plugin_in_deallocate_test") { + new_test = new DeletePluginInDeallocateTest(instance, host_functions); } return new_test; diff --git a/webkit/tools/test_shell/test_shell.gypi b/webkit/tools/test_shell/test_shell.gypi index 256376d..7281d83 100644 --- a/webkit/tools/test_shell/test_shell.gypi +++ b/webkit/tools/test_shell/test_shell.gypi @@ -583,6 +583,8 @@ '../../plugins/npapi/test/plugin_arguments_test.h', '../../plugins/npapi/test/plugin_create_instance_in_paint.cc', '../../plugins/npapi/test/plugin_create_instance_in_paint.h', + '../../plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.cc', + '../../plugins/npapi/test/plugin_delete_plugin_in_deallocate_test.h', '../../plugins/npapi/test/plugin_delete_plugin_in_stream_test.cc', '../../plugins/npapi/test/plugin_delete_plugin_in_stream_test.h', '../../plugins/npapi/test/plugin_get_javascript_url_test.cc', |