This source file includes following definitions.
- GetHTMLForBrowserPluginObject
- AllowBrowserPlugin
- CreateBrowserPluginManager
- GetInstance
- SetUp
- TearDown
- CreateContentRendererClient
- ExecuteScriptAndReturnString
- ExecuteScriptAndReturnInt
- ExecuteScriptAndReturnBool
- GetCurrentPlugin
- GetCurrentPluginWithAttachParams
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "content/renderer/browser_plugin/browser_plugin_browsertest.h"
#include "base/debug/leak_annotations.h"
#include "base/files/file_path.h"
#include "base/memory/singleton.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "content/public/common/content_constants.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/browser_plugin/browser_plugin.h"
#include "content/renderer/browser_plugin/browser_plugin_manager_factory.h"
#include "content/renderer/browser_plugin/mock_browser_plugin.h"
#include "content/renderer/browser_plugin/mock_browser_plugin_manager.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/renderer_webkitplatformsupport_impl.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/public/platform/WebCursorInfo.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
namespace content {
namespace {
const char kHTMLForBrowserPluginObject[] =
"<object id='browserplugin' width='640px' height='480px'"
" src='foo' type='%s'></object>"
"<script>document.querySelector('object').nonExistentAttribute;</script>";
const char kHTMLForBrowserPluginWithAllAttributes[] =
"<object id='browserplugin' width='640' height='480' type='%s'"
" autosize maxheight='600' maxwidth='800' minheight='240'"
" minwidth='320' name='Jim' partition='someid' src='foo'>";
const char kHTMLForSourcelessPluginObject[] =
"<object id='browserplugin' width='640px' height='480px' type='%s'>";
const char kHTMLForPartitionedPluginObject[] =
"<object id='browserplugin' width='640px' height='480px'"
" src='foo' type='%s' partition='someid'>";
const char kHTMLForInvalidPartitionedPluginObject[] =
"<object id='browserplugin' width='640px' height='480px'"
" type='%s' partition='persist:'>";
const char kHTMLForPartitionedPersistedPluginObject[] =
"<object id='browserplugin' width='640px' height='480px'"
" src='foo' type='%s' partition='persist:someid'>";
std::string GetHTMLForBrowserPluginObject() {
return base::StringPrintf(kHTMLForBrowserPluginObject,
kBrowserPluginMimeType);
}
}
class TestContentRendererClient : public ContentRendererClient {
public:
TestContentRendererClient() : ContentRendererClient() {
}
virtual ~TestContentRendererClient() {
}
virtual bool AllowBrowserPlugin(
blink::WebPluginContainer* container) OVERRIDE {
return true;
}
};
class TestBrowserPluginManagerFactory : public BrowserPluginManagerFactory {
public:
virtual MockBrowserPluginManager* CreateBrowserPluginManager(
RenderViewImpl* render_view) OVERRIDE {
return new MockBrowserPluginManager(render_view);
}
static TestBrowserPluginManagerFactory* GetInstance() {
return Singleton<TestBrowserPluginManagerFactory>::get();
}
protected:
TestBrowserPluginManagerFactory() {}
virtual ~TestBrowserPluginManagerFactory() {}
private:
friend struct DefaultSingletonTraits<TestBrowserPluginManagerFactory>;
DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginManagerFactory);
};
BrowserPluginTest::BrowserPluginTest() {}
BrowserPluginTest::~BrowserPluginTest() {}
void BrowserPluginTest::SetUp() {
BrowserPluginManager::set_factory_for_testing(
TestBrowserPluginManagerFactory::GetInstance());
content::RenderViewTest::SetUp();
}
void BrowserPluginTest::TearDown() {
BrowserPluginManager::set_factory_for_testing(
TestBrowserPluginManagerFactory::GetInstance());
#if defined(LEAK_SANITIZER)
__lsan_do_leak_check();
#endif
RenderViewTest::TearDown();
}
ContentRendererClient* BrowserPluginTest::CreateContentRendererClient() {
return new TestContentRendererClient;
}
std::string BrowserPluginTest::ExecuteScriptAndReturnString(
const std::string& script) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str())));
if (value.IsEmpty() || !value->IsString())
return std::string();
v8::Local<v8::String> v8_str = value->ToString();
int length = v8_str->Utf8Length() + 1;
scoped_ptr<char[]> str(new char[length]);
v8_str->WriteUtf8(str.get(), length);
return str.get();
}
int BrowserPluginTest::ExecuteScriptAndReturnInt(
const std::string& script) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str())));
if (value.IsEmpty() || !value->IsInt32())
return 0;
return value->Int32Value();
}
bool BrowserPluginTest::ExecuteScriptAndReturnBool(
const std::string& script, bool* result) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
blink::WebScriptSource(blink::WebString::fromUTF8(script.c_str())));
if (value.IsEmpty() || !value->IsBoolean())
return false;
*result = value->BooleanValue();
return true;
}
MockBrowserPlugin* BrowserPluginTest::GetCurrentPlugin() {
BrowserPluginHostMsg_Attach_Params params;
return GetCurrentPluginWithAttachParams(¶ms);
}
MockBrowserPlugin* BrowserPluginTest::GetCurrentPluginWithAttachParams(
BrowserPluginHostMsg_Attach_Params* params) {
int instance_id = 0;
const IPC::Message* msg =
browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_Attach::ID);
if (!msg)
return NULL;
PickleIterator iter(*msg);
if (!iter.ReadInt(&instance_id))
return NULL;
if (!IPC::ParamTraits<BrowserPluginHostMsg_Attach_Params>::Read(
msg, &iter, params))
return NULL;
MockBrowserPlugin* browser_plugin = static_cast<MockBrowserPlugin*>(
browser_plugin_manager()->GetBrowserPlugin(instance_id));
BrowserPluginMsg_Attach_ACK_Params attach_ack_params;
browser_plugin->OnAttachACK(instance_id, attach_ack_params);
return browser_plugin;
}
TEST_F(BrowserPluginTest, InitialResize) {
LoadHTML(GetHTMLForBrowserPluginObject().c_str());
BrowserPluginHostMsg_Attach_Params params;
MockBrowserPlugin* browser_plugin = GetCurrentPluginWithAttachParams(¶ms);
EXPECT_EQ(640, params.resize_guest_params.view_rect.width());
EXPECT_EQ(480, params.resize_guest_params.view_rect.height());
ASSERT_TRUE(browser_plugin);
int instance_id = browser_plugin->guest_instance_id();
EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
BrowserPluginMsg_UpdateRect_Params update_rect_params;
update_rect_params.damage_buffer_sequence_id =
browser_plugin->damage_buffer_sequence_id_;
update_rect_params.view_size = gfx::Size(640, 480);
update_rect_params.scale_factor = 1.0f;
update_rect_params.is_resize_ack = true;
update_rect_params.needs_ack = true;
BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
browser_plugin->OnMessageReceived(msg);
EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
}
TEST_F(BrowserPluginTest, ParseAllAttributes) {
std::string html = base::StringPrintf(kHTMLForBrowserPluginWithAllAttributes,
kBrowserPluginMimeType);
LoadHTML(html.c_str());
bool result;
bool has_value = ExecuteScriptAndReturnBool(
"document.getElementById('browserplugin').autosize", &result);
EXPECT_TRUE(has_value);
EXPECT_TRUE(result);
int maxHeight = ExecuteScriptAndReturnInt(
"document.getElementById('browserplugin').maxheight");
EXPECT_EQ(600, maxHeight);
int maxWidth = ExecuteScriptAndReturnInt(
"document.getElementById('browserplugin').maxwidth");
EXPECT_EQ(800, maxWidth);
int minHeight = ExecuteScriptAndReturnInt(
"document.getElementById('browserplugin').minheight");
EXPECT_EQ(240, minHeight);
int minWidth = ExecuteScriptAndReturnInt(
"document.getElementById('browserplugin').minwidth");
EXPECT_EQ(320, minWidth);
std::string name = ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').name");
EXPECT_STREQ("Jim", name.c_str());
std::string partition = ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').partition");
EXPECT_STREQ("someid", partition.c_str());
std::string src = ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').src");
EXPECT_STREQ("foo", src.c_str());
}
TEST_F(BrowserPluginTest, SrcAttribute) {
LoadHTML(GetHTMLForBrowserPluginObject().c_str());
{
BrowserPluginHostMsg_Attach_Params params;
MockBrowserPlugin* browser_plugin =
GetCurrentPluginWithAttachParams(¶ms);
ASSERT_TRUE(browser_plugin);
EXPECT_EQ("foo", params.src);
}
browser_plugin_manager()->sink().ClearMessages();
ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
{
const IPC::Message* create_msg =
browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_Attach::ID);
ASSERT_FALSE(create_msg);
const IPC::Message* msg =
browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_NavigateGuest::ID);
ASSERT_TRUE(msg);
int instance_id = 0;
std::string src;
BrowserPluginHostMsg_NavigateGuest::Read(msg, &instance_id, &src);
EXPECT_EQ("bar", src);
std::string src_value =
ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').src");
EXPECT_EQ("bar", src_value);
}
}
TEST_F(BrowserPluginTest, ResizeFlowControl) {
LoadHTML(GetHTMLForBrowserPluginObject().c_str());
MockBrowserPlugin* browser_plugin = GetCurrentPlugin();
ASSERT_TRUE(browser_plugin);
int instance_id = browser_plugin->guest_instance_id();
EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
{
BrowserPluginMsg_UpdateRect_Params update_rect_params;
update_rect_params.view_size = gfx::Size(640, 480);
update_rect_params.scale_factor = 1.0f;
update_rect_params.is_resize_ack = true;
update_rect_params.needs_ack = true;
update_rect_params.damage_buffer_sequence_id =
browser_plugin->damage_buffer_sequence_id_;
BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
browser_plugin->OnMessageReceived(msg);
EXPECT_EQ(NULL, browser_plugin->pending_damage_buffer_.get());
}
browser_plugin_manager()->sink().ClearMessages();
ExecuteJavaScript("document.getElementById('browserplugin').width = '641px'");
GetMainFrame()->view()->layout();
ProcessPendingMessages();
ExecuteJavaScript("document.getElementById('browserplugin').width = '642px'");
GetMainFrame()->view()->layout();
ProcessPendingMessages();
ExecuteJavaScript("document.getElementById('browserplugin').width = '643px'");
GetMainFrame()->view()->layout();
ProcessPendingMessages();
EXPECT_LE(1u, browser_plugin_manager()->sink().message_count());
for (size_t i = 0; i < browser_plugin_manager()->sink().message_count();
++i) {
const IPC::Message* msg = browser_plugin_manager()->sink().GetMessageAt(i);
if (msg->type() != BrowserPluginHostMsg_ResizeGuest::ID)
EXPECT_EQ(msg->type(), BrowserPluginHostMsg_UpdateGeometry::ID);
}
const IPC::Message* msg =
browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_ResizeGuest::ID);
ASSERT_TRUE(msg);
BrowserPluginHostMsg_ResizeGuest_Params params;
BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, ¶ms);
EXPECT_EQ(641, params.view_rect.width());
EXPECT_EQ(480, params.view_rect.height());
EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
{
BrowserPluginMsg_UpdateRect_Params update_rect_params;
update_rect_params.view_size = gfx::Size(641, 480);
update_rect_params.scale_factor = 1.0f;
update_rect_params.is_resize_ack = true;
update_rect_params.needs_ack = true;
update_rect_params.damage_buffer_sequence_id =
browser_plugin->damage_buffer_sequence_id_;
BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
browser_plugin->OnMessageReceived(msg);
EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
}
{
BrowserPluginMsg_UpdateRect_Params update_rect_params;
update_rect_params.view_size = gfx::Size(643, 480);
update_rect_params.scale_factor = 1.0f;
update_rect_params.is_resize_ack = true;
update_rect_params.needs_ack = true;
update_rect_params.damage_buffer_sequence_id =
browser_plugin->damage_buffer_sequence_id_;
BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
browser_plugin->OnMessageReceived(msg);
EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
}
}
TEST_F(BrowserPluginTest, RemovePlugin) {
LoadHTML(GetHTMLForBrowserPluginObject().c_str());
EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_PluginDestroyed::ID));
ExecuteJavaScript("x = document.getElementById('browserplugin'); "
"x.parentNode.removeChild(x);");
ProcessPendingMessages();
EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_PluginDestroyed::ID));
}
TEST_F(BrowserPluginTest, RemovePluginBeforeNavigation) {
std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
kBrowserPluginMimeType);
LoadHTML(html.c_str());
EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_PluginDestroyed::ID));
ExecuteJavaScript("x = document.getElementById('browserplugin'); "
"x.parentNode.removeChild(x);");
ProcessPendingMessages();
EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_PluginDestroyed::ID));
}
TEST_F(BrowserPluginTest, PartitionAttribute) {
std::string html = base::StringPrintf(kHTMLForPartitionedPluginObject,
kBrowserPluginMimeType);
LoadHTML(html.c_str());
std::string partition_value = ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').partition");
EXPECT_STREQ("someid", partition_value.c_str());
html = base::StringPrintf(kHTMLForPartitionedPersistedPluginObject,
kBrowserPluginMimeType);
LoadHTML(html.c_str());
partition_value = ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').partition");
EXPECT_STREQ("persist:someid", partition_value.c_str());
ExecuteJavaScript(
"try {"
" document.getElementById('browserplugin').partition = 'foo';"
" document.title = 'success';"
"} catch (e) { document.title = e.message; }");
std::string title = ExecuteScriptAndReturnString("document.title");
EXPECT_STREQ(
"The object has already navigated, so its partition cannot be changed.",
title.c_str());
html = base::StringPrintf(kHTMLForSourcelessPluginObject,
kBrowserPluginMimeType);
LoadHTML(html.c_str());
ExecuteJavaScript(
"try {"
" document.getElementById('browserplugin').partition = 'persist:';"
" document.title = 'success';"
"} catch (e) { document.title = e.message; }");
title = ExecuteScriptAndReturnString("document.title");
EXPECT_STREQ("Invalid partition attribute.", title.c_str());
}
TEST_F(BrowserPluginTest, InvalidPartition) {
std::string html = base::StringPrintf(kHTMLForInvalidPartitionedPluginObject,
kBrowserPluginMimeType);
LoadHTML(html.c_str());
{
ExecuteJavaScript(
"try {"
" document.getElementById('browserplugin').src = 'bar';"
" document.title = 'success';"
"} catch (e) { document.title = e.message; }");
std::string title = ExecuteScriptAndReturnString("document.title");
EXPECT_STREQ("Invalid partition attribute.", title.c_str());
EXPECT_EQ("", ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').src"));
}
ExecuteJavaScript(
"document.getElementById('browserplugin').partition = 'persist:foo'");
ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
EXPECT_EQ("bar", ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').src"));
ProcessPendingMessages();
{
ExecuteJavaScript(
"try {"
" document.getElementById('browserplugin').partition = 'persist:1337';"
" document.title = 'success';"
"} catch (e) { document.title = e.message; }");
std::string title = ExecuteScriptAndReturnString("document.title");
EXPECT_STREQ(
"The object has already navigated, so its partition cannot be changed.",
title.c_str());
ExecuteJavaScript("document.getElementById('browserplugin').src = '42'");
EXPECT_EQ("42", ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').src"));
}
}
TEST_F(BrowserPluginTest, ImmutableAttributesAfterNavigation) {
std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
kBrowserPluginMimeType);
LoadHTML(html.c_str());
ExecuteJavaScript(
"document.getElementById('browserplugin').partition = 'storage'");
std::string partition_value = ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').partition");
EXPECT_STREQ("storage", partition_value.c_str());
std::string src_value = ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').src");
EXPECT_STREQ("", src_value.c_str());
ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
ProcessPendingMessages();
{
BrowserPluginHostMsg_Attach_Params params;
MockBrowserPlugin* browser_plugin =
GetCurrentPluginWithAttachParams(¶ms);
ASSERT_TRUE(browser_plugin);
EXPECT_STREQ("storage", params.storage_partition_id.c_str());
EXPECT_FALSE(params.persist_storage);
EXPECT_STREQ("bar", params.src.c_str());
}
ExecuteJavaScript(
"try {"
" document.getElementById('browserplugin').partition = 'someid';"
" document.title = 'success';"
"} catch (e) { document.title = e.message; }");
std::string title = ExecuteScriptAndReturnString("document.title");
EXPECT_STREQ(
"The object has already navigated, so its partition cannot be changed.",
title.c_str());
partition_value = ExecuteScriptAndReturnString(
"document.getElementById('browserplugin').partition");
EXPECT_STREQ("storage", partition_value.c_str());
}
TEST_F(BrowserPluginTest, AutoSizeAttributes) {
std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
kBrowserPluginMimeType);
LoadHTML(html.c_str());
const char* kSetAutoSizeParametersAndNavigate =
"var browserplugin = document.getElementById('browserplugin');"
"browserplugin.autosize = true;"
"browserplugin.minwidth = 42;"
"browserplugin.minheight = 43;"
"browserplugin.maxwidth = 1337;"
"browserplugin.maxheight = 1338;"
"browserplugin.src = 'foobar';";
const char* kDisableAutoSize =
"document.getElementById('browserplugin').removeAttribute('autosize');";
int instance_id = 0;
ExecuteJavaScript(kSetAutoSizeParametersAndNavigate);
ProcessPendingMessages();
BrowserPluginHostMsg_Attach_Params params;
MockBrowserPlugin* browser_plugin =
GetCurrentPluginWithAttachParams(¶ms);
ASSERT_TRUE(browser_plugin);
EXPECT_TRUE(params.auto_size_params.enable);
EXPECT_EQ(42, params.auto_size_params.min_size.width());
EXPECT_EQ(43, params.auto_size_params.min_size.height());
EXPECT_EQ(1337, params.auto_size_params.max_size.width());
EXPECT_EQ(1338, params.auto_size_params.max_size.height());
EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
ExecuteJavaScript(kDisableAutoSize);
ProcessPendingMessages();
const IPC::Message* auto_size_msg =
browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_SetAutoSize::ID);
EXPECT_FALSE(auto_size_msg);
BrowserPluginMsg_UpdateRect_Params update_rect_params;
update_rect_params.damage_buffer_sequence_id =
browser_plugin->damage_buffer_sequence_id_;
update_rect_params.view_size = gfx::Size(1337, 1338);
update_rect_params.scale_factor = 1.0f;
update_rect_params.is_resize_ack = true;
update_rect_params.needs_ack = true;
BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
browser_plugin->OnMessageReceived(msg);
{
const IPC::Message* auto_size_msg =
browser_plugin_manager()->sink().GetUniqueMessageMatching(
BrowserPluginHostMsg_UpdateRect_ACK::ID);
ASSERT_TRUE(auto_size_msg);
int instance_id = 0;
bool needs_ack = false;
BrowserPluginHostMsg_AutoSize_Params auto_size_params;
BrowserPluginHostMsg_ResizeGuest_Params resize_params;
BrowserPluginHostMsg_UpdateRect_ACK::Read(auto_size_msg,
&instance_id,
&needs_ack,
&auto_size_params,
&resize_params);
EXPECT_FALSE(auto_size_params.enable);
EXPECT_EQ(0, auto_size_params.min_size.width());
EXPECT_EQ(0, auto_size_params.min_size.height());
EXPECT_EQ(0, auto_size_params.max_size.width());
EXPECT_EQ(0, auto_size_params.max_size.height());
}
}
}