1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/browser_plugin/browser_plugin_browsertest.h"
7 #include "base/file_path.h"
8 #include "base/file_util.h"
9 #include "base/memory/singleton.h"
10 #include "base/path_service.h"
11 #include "content/common/browser_plugin_messages.h"
12 #include "content/public/common/content_constants.h"
13 #include "content/renderer/browser_plugin/browser_plugin.h"
14 #include "content/renderer/browser_plugin/browser_plugin_manager_factory.h"
15 #include "content/renderer/browser_plugin/mock_browser_plugin.h"
16 #include "content/renderer/browser_plugin/mock_browser_plugin_manager.h"
17 #include "content/renderer/render_thread_impl.h"
18 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
19 #include "skia/ext/platform_canvas.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h"
25 const char kHTMLForBrowserPluginObject
[] =
26 "<object id='browserplugin' width='640px' height='480px'"
27 " src='foo' type='%s'>";
29 const char kHTMLForSourcelessPluginObject
[] =
30 "<object id='browserplugin' width='640px' height='480px' type='%s'>";
32 const char kHTMLForPartitionedPluginObject
[] =
33 "<object id='browserplugin' width='640px' height='480px'"
34 " src='foo' type='%s' partition='someid'>";
36 const char kHTMLForInvalidPartitionedPluginObject
[] =
37 "<object id='browserplugin' width='640px' height='480px'"
38 " type='%s' partition='persist:'>";
40 const char kHTMLForPartitionedPersistedPluginObject
[] =
41 "<object id='browserplugin' width='640px' height='480px'"
42 " src='foo' type='%s' partition='persist:someid'>";
44 std::string
GetHTMLForBrowserPluginObject() {
45 return StringPrintf(kHTMLForBrowserPluginObject
,
46 content::kBrowserPluginMimeType
);
53 // Test factory for creating test instances of BrowserPluginManager.
54 class TestBrowserPluginManagerFactory
: public BrowserPluginManagerFactory
{
56 virtual MockBrowserPluginManager
* CreateBrowserPluginManager(
57 RenderViewImpl
* render_view
) OVERRIDE
{
58 return new MockBrowserPluginManager(render_view
);
62 static TestBrowserPluginManagerFactory
* GetInstance() {
63 return Singleton
<TestBrowserPluginManagerFactory
>::get();
67 TestBrowserPluginManagerFactory() {}
68 virtual ~TestBrowserPluginManagerFactory() {}
72 friend struct DefaultSingletonTraits
<TestBrowserPluginManagerFactory
>;
74 DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginManagerFactory
);
77 BrowserPluginTest::BrowserPluginTest() {}
79 BrowserPluginTest::~BrowserPluginTest() {}
81 void BrowserPluginTest::SetUp() {
82 GetContentClient()->set_renderer_for_testing(&content_renderer_client_
);
83 BrowserPluginManager::set_factory_for_testing(
84 TestBrowserPluginManagerFactory::GetInstance());
85 content::RenderViewTest::SetUp();
89 void BrowserPluginTest::TearDown() {
90 browser_plugin_manager()->Cleanup();
91 BrowserPluginManager::set_factory_for_testing(
92 TestBrowserPluginManagerFactory::GetInstance());
93 content::RenderViewTest::TearDown();
96 std::string
BrowserPluginTest::ExecuteScriptAndReturnString(
97 const std::string
& script
) {
98 v8::Handle
<v8::Value
> value
= GetMainFrame()->executeScriptAndReturnValue(
99 WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script
.c_str())));
100 if (value
.IsEmpty() || !value
->IsString())
101 return std::string();
103 v8::Local
<v8::String
> v8_str
= value
->ToString();
104 int length
= v8_str
->Utf8Length() + 1;
105 scoped_array
<char> str(new char[length
]);
106 v8_str
->WriteUtf8(str
.get(), length
);
110 int BrowserPluginTest::ExecuteScriptAndReturnInt(
111 const std::string
& script
) {
112 v8::Handle
<v8::Value
> value
= GetMainFrame()->executeScriptAndReturnValue(
113 WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script
.c_str())));
114 if (value
.IsEmpty() || !value
->IsInt32())
117 return value
->Int32Value();
120 // This test verifies that an initial resize occurs when we instantiate the
121 // browser plugin. This test also verifies that the browser plugin is waiting
122 // for a BrowserPluginMsg_UpdateRect in response. We issue an UpdateRect, and
123 // we observe an UpdateRect_ACK, with the |pending_damage_buffer_| reset,
124 // indiciating that the BrowserPlugin is not waiting for any more UpdateRects to
125 // satisfy its resize request.
126 TEST_F(BrowserPluginTest
, InitialResize
) {
127 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
128 // Verify that the information based on ResizeGuest is correct, and
129 // use its TransportDIB::Id to paint.
132 const IPC::Message
* msg
=
133 browser_plugin_manager()->sink().GetUniqueMessageMatching(
134 BrowserPluginHostMsg_ResizeGuest::ID
);
136 BrowserPluginHostMsg_ResizeGuest_Params params
;
137 BrowserPluginHostMsg_ResizeGuest::Read(msg
, &instance_id
, ¶ms
);
138 EXPECT_EQ(640, params
.view_size
.width());
139 EXPECT_EQ(480, params
.view_size
.height());
142 MockBrowserPlugin
* browser_plugin
=
143 static_cast<MockBrowserPlugin
*>(
144 browser_plugin_manager()->GetBrowserPlugin(instance_id
));
145 ASSERT_TRUE(browser_plugin
);
146 // Now the browser plugin is expecting a UpdateRect resize.
147 EXPECT_TRUE(browser_plugin
->pending_damage_buffer_
);
149 // Send the BrowserPlugin an UpdateRect equal to its container size with
150 // the same damage buffer. That should clear |pending_damage_buffer_|.
151 BrowserPluginMsg_UpdateRect_Params update_rect_params
;
152 update_rect_params
.damage_buffer_identifier
=
153 #if defined(OS_MACOSX)
154 browser_plugin
->pending_damage_buffer_
->id();
156 browser_plugin
->pending_damage_buffer_
->handle();
158 update_rect_params
.view_size
= gfx::Size(640, 480);
159 update_rect_params
.scale_factor
= 1.0f
;
160 update_rect_params
.is_resize_ack
= true;
161 BrowserPluginMsg_UpdateRect
msg(0, instance_id
, 0, update_rect_params
);
162 browser_plugin
->OnMessageReceived(msg
);
163 EXPECT_FALSE(browser_plugin
->pending_damage_buffer_
);
166 // Verify that the src attribute on the browser plugin works as expected.
167 TEST_F(BrowserPluginTest
, SrcAttribute
) {
168 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
169 // Verify that we're reporting the correct URL to navigate to based on the
172 // Ensure we get a CreateGuest on the initial navigation.
173 const IPC::Message
* create_msg
=
174 browser_plugin_manager()->sink().GetUniqueMessageMatching(
175 BrowserPluginHostMsg_CreateGuest::ID
);
176 ASSERT_TRUE(create_msg
);
178 const IPC::Message
* msg
=
179 browser_plugin_manager()->sink().GetUniqueMessageMatching(
180 BrowserPluginHostMsg_NavigateGuest::ID
);
185 BrowserPluginHostMsg_NavigateGuest::Read(msg
, &instance_id
, &src
);
186 EXPECT_EQ("foo", src
);
189 browser_plugin_manager()->sink().ClearMessages();
190 // Navigate to bar and observe the associated
191 // BrowserPluginHostMsg_NavigateGuest message.
192 // Verify that the src attribute is updated as well.
193 ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
195 // Verify that we do not get a CreateGuest on subsequent navigations.
196 const IPC::Message
* create_msg
=
197 browser_plugin_manager()->sink().GetUniqueMessageMatching(
198 BrowserPluginHostMsg_CreateGuest::ID
);
199 ASSERT_FALSE(create_msg
);
201 const IPC::Message
* msg
=
202 browser_plugin_manager()->sink().GetUniqueMessageMatching(
203 BrowserPluginHostMsg_NavigateGuest::ID
);
208 BrowserPluginHostMsg_NavigateGuest::Read(msg
, &instance_id
, &src
);
209 EXPECT_EQ("bar", src
);
210 std::string src_value
=
211 ExecuteScriptAndReturnString(
212 "document.getElementById('browserplugin').src");
213 EXPECT_EQ("bar", src_value
);
217 TEST_F(BrowserPluginTest
, ResizeFlowControl
) {
218 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
221 // Ensure we get a NavigateGuest on the initial navigation and grab the
222 // BrowserPlugin's instance_id from there.
224 const IPC::Message
* nav_msg
=
225 browser_plugin_manager()->sink().GetUniqueMessageMatching(
226 BrowserPluginHostMsg_NavigateGuest::ID
);
227 ASSERT_TRUE(nav_msg
);
228 BrowserPluginHostMsg_NavigateGuest::Read(nav_msg
, &instance_id
, &src
);
230 MockBrowserPlugin
* browser_plugin
=
231 static_cast<MockBrowserPlugin
*>(
232 browser_plugin_manager()->GetBrowserPlugin(instance_id
));
233 ASSERT_TRUE(browser_plugin
);
234 EXPECT_TRUE(browser_plugin
->pending_damage_buffer_
);
235 // Send an UpdateRect to the BrowserPlugin to make it use the pending damage
238 // We send a stale UpdateRect to the BrowserPlugin.
239 BrowserPluginMsg_UpdateRect_Params update_rect_params
;
240 update_rect_params
.view_size
= gfx::Size(640, 480);
241 update_rect_params
.scale_factor
= 1.0f
;
242 update_rect_params
.is_resize_ack
= true;
243 // By sending the damage buffer handle back to BrowserPlugin on UpdateRect,
244 // then the BrowserPlugin knows that the browser process has received and
245 // has begun to use the pending_damage_buffer.
246 update_rect_params
.damage_buffer_identifier
=
247 #if defined(OS_MACOSX)
248 browser_plugin
->pending_damage_buffer_
->id();
250 browser_plugin
->pending_damage_buffer_
->handle();
252 BrowserPluginMsg_UpdateRect
msg(0, instance_id
, 0, update_rect_params
);
253 browser_plugin
->OnMessageReceived(msg
);
254 EXPECT_EQ(NULL
, browser_plugin
->pending_damage_buffer_
);
257 browser_plugin_manager()->sink().ClearMessages();
259 // Resize the browser plugin three times.
260 ExecuteJavaScript("document.getElementById('browserplugin').width = '641px'");
261 ProcessPendingMessages();
262 ExecuteJavaScript("document.getElementById('browserplugin').width = '642px'");
263 ProcessPendingMessages();
264 ExecuteJavaScript("document.getElementById('browserplugin').width = '643px'");
265 ProcessPendingMessages();
267 // Expect to see one messsage in the sink. BrowserPlugin will not issue
268 // subsequent resize requests until the first request is satisfied by the
270 EXPECT_EQ(1u, browser_plugin_manager()->sink().message_count());
271 const IPC::Message
* msg
=
272 browser_plugin_manager()->sink().GetFirstMessageMatching(
273 BrowserPluginHostMsg_ResizeGuest::ID
);
275 BrowserPluginHostMsg_ResizeGuest_Params params
;
276 BrowserPluginHostMsg_ResizeGuest::Read(msg
, &instance_id
, ¶ms
);
277 EXPECT_EQ(641, params
.view_size
.width());
278 EXPECT_EQ(480, params
.view_size
.height());
279 // This indicates that the BrowserPlugin has sent out a previous resize
280 // request but has not yet received an UpdateRect for that request.
281 EXPECT_TRUE(browser_plugin
->pending_damage_buffer_
);
284 // We send a stale UpdateRect to the BrowserPlugin.
285 BrowserPluginMsg_UpdateRect_Params update_rect_params
;
286 update_rect_params
.view_size
= gfx::Size(641, 480);
287 update_rect_params
.scale_factor
= 1.0f
;
288 update_rect_params
.is_resize_ack
= true;
289 update_rect_params
.damage_buffer_identifier
=
290 #if defined(OS_MACOSX)
291 browser_plugin
->pending_damage_buffer_
->id();
293 browser_plugin
->pending_damage_buffer_
->handle();
295 BrowserPluginMsg_UpdateRect
msg(0, instance_id
, 0, update_rect_params
);
296 browser_plugin
->OnMessageReceived(msg
);
297 // This tells us that the BrowserPlugin is still expecting another
298 // UpdateRect with the most recent size.
299 EXPECT_TRUE(browser_plugin
->pending_damage_buffer_
);
301 // Send the BrowserPlugin another UpdateRect, but this time with a size
302 // that matches the size of the container.
304 BrowserPluginMsg_UpdateRect_Params update_rect_params
;
305 update_rect_params
.view_size
= gfx::Size(643, 480);
306 update_rect_params
.scale_factor
= 1.0f
;
307 update_rect_params
.is_resize_ack
= true;
308 update_rect_params
.damage_buffer_identifier
=
309 #if defined(OS_MACOSX)
310 browser_plugin
->pending_damage_buffer_
->id();
312 browser_plugin
->pending_damage_buffer_
->handle();
314 BrowserPluginMsg_UpdateRect
msg(0, instance_id
, 0, update_rect_params
);
315 browser_plugin
->OnMessageReceived(msg
);
316 // The BrowserPlugin has finally received an UpdateRect that satisifes
317 // its current size, and so it is happy.
318 EXPECT_FALSE(browser_plugin
->pending_damage_buffer_
);
322 TEST_F(BrowserPluginTest
, GuestCrash
) {
323 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
325 // Grab the BrowserPlugin's instance ID from its resize message.
328 const IPC::Message
* msg
=
329 browser_plugin_manager()->sink().GetFirstMessageMatching(
330 BrowserPluginHostMsg_ResizeGuest::ID
);
332 BrowserPluginHostMsg_ResizeGuest_Params params
;
333 BrowserPluginHostMsg_ResizeGuest::Read(msg
, &instance_id
, ¶ms
);
335 MockBrowserPlugin
* browser_plugin
=
336 static_cast<MockBrowserPlugin
*>(
337 browser_plugin_manager()->GetBrowserPlugin(instance_id
));
338 ASSERT_TRUE(browser_plugin
);
340 WebKit::WebCursorInfo cursor_info
;
341 // Send an event and verify that the event is deported.
342 browser_plugin
->handleInputEvent(WebKit::WebMouseEvent(),
344 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
345 BrowserPluginHostMsg_HandleInputEvent::ID
));
346 browser_plugin_manager()->sink().ClearMessages();
348 const char* kAddEventListener
=
350 "function exitListener(e) {"
351 " msg = JSON.parse(e.detail).reason;"
353 "document.getElementById('browserplugin')."
354 " addEventListener('-internal-exit', exitListener);";
356 ExecuteJavaScript(kAddEventListener
);
358 // Pretend that the guest has terminated normally.
360 BrowserPluginMsg_GuestGone
msg(
361 0, 0, 0, base::TERMINATION_STATUS_NORMAL_TERMINATION
);
362 browser_plugin
->OnMessageReceived(msg
);
365 // Verify that our event listener has fired.
366 EXPECT_EQ("normal", ExecuteScriptAndReturnString("msg"));
368 // Pretend that the guest has crashed.
370 BrowserPluginMsg_GuestGone
msg(
371 0, 0, 0, base::TERMINATION_STATUS_PROCESS_CRASHED
);
372 browser_plugin
->OnMessageReceived(msg
);
375 // Verify that our event listener has fired.
376 EXPECT_EQ("crashed", ExecuteScriptAndReturnString("msg"));
378 // Send an event and verify that events are no longer deported.
379 browser_plugin
->handleInputEvent(WebKit::WebMouseEvent(),
381 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
382 BrowserPluginHostMsg_HandleInputEvent::ID
));
385 TEST_F(BrowserPluginTest
, RemovePlugin
) {
386 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
387 EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
388 BrowserPluginHostMsg_PluginDestroyed::ID
));
389 ExecuteJavaScript("x = document.getElementById('browserplugin'); "
390 "x.parentNode.removeChild(x);");
391 ProcessPendingMessages();
392 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
393 BrowserPluginHostMsg_PluginDestroyed::ID
));
396 TEST_F(BrowserPluginTest
, CustomEvents
) {
397 const char* kAddEventListener
=
400 " url = JSON.parse(e.detail).url;"
402 "document.getElementById('browserplugin')."
403 " addEventListener('-internal-loadcommit', nav);";
404 const char* kRemoveEventListener
=
405 "document.getElementById('browserplugin')."
406 " removeEventListener('-internal-loadcommit', nav);";
407 const char* kGetProcessID
=
408 "document.getElementById('browserplugin').getProcessId()";
409 const char* kGetSrc
=
410 "document.getElementById('browserplugin').src";
411 const char* kGoogleURL
= "http://www.google.com/";
412 const char* kGoogleNewsURL
= "http://news.google.com/";
414 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
415 ExecuteJavaScript(kAddEventListener
);
416 // Grab the BrowserPlugin's instance ID from its resize message.
417 const IPC::Message
* msg
=
418 browser_plugin_manager()->sink().GetFirstMessageMatching(
419 BrowserPluginHostMsg_ResizeGuest::ID
);
422 BrowserPluginHostMsg_ResizeGuest_Params params
;
423 BrowserPluginHostMsg_ResizeGuest::Read(msg
, &instance_id
, ¶ms
);
425 MockBrowserPlugin
* browser_plugin
=
426 static_cast<MockBrowserPlugin
*>(
427 browser_plugin_manager()->GetBrowserPlugin(instance_id
));
428 ASSERT_TRUE(browser_plugin
);
431 BrowserPluginMsg_LoadCommit_Params navigate_params
;
432 navigate_params
.is_top_level
= true;
433 navigate_params
.url
= GURL(kGoogleURL
);
434 navigate_params
.process_id
= 1337;
435 BrowserPluginMsg_LoadCommit
msg(0, instance_id
, navigate_params
);
436 browser_plugin
->OnMessageReceived(msg
);
437 EXPECT_EQ(kGoogleURL
, ExecuteScriptAndReturnString("url"));
438 EXPECT_EQ(kGoogleURL
, ExecuteScriptAndReturnString(kGetSrc
));
439 EXPECT_EQ(1337, ExecuteScriptAndReturnInt(kGetProcessID
));
441 ExecuteJavaScript(kRemoveEventListener
);
443 BrowserPluginMsg_LoadCommit_Params navigate_params
;
444 navigate_params
.is_top_level
= false;
445 navigate_params
.url
= GURL(kGoogleNewsURL
);
446 navigate_params
.process_id
= 42;
447 BrowserPluginMsg_LoadCommit
msg(0, instance_id
, navigate_params
);
448 browser_plugin
->OnMessageReceived(msg
);
449 // The URL variable should not change because we've removed the event
451 EXPECT_EQ(kGoogleURL
, ExecuteScriptAndReturnString("url"));
452 // The src attribute should not change if this is a top-level navigation.
453 EXPECT_EQ(kGoogleURL
, ExecuteScriptAndReturnString(kGetSrc
));
454 EXPECT_EQ(42, ExecuteScriptAndReturnInt(kGetProcessID
));
458 TEST_F(BrowserPluginTest
, StopMethod
) {
459 const char* kCallStop
=
460 "document.getElementById('browserplugin').stop();";
461 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
462 ExecuteJavaScript(kCallStop
);
463 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
464 BrowserPluginHostMsg_Stop::ID
));
467 TEST_F(BrowserPluginTest
, ReloadMethod
) {
468 const char* kCallReload
=
469 "document.getElementById('browserplugin').reload();";
470 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
471 ExecuteJavaScript(kCallReload
);
472 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
473 BrowserPluginHostMsg_Reload::ID
));
477 // Verify that the 'partition' attribute on the browser plugin is parsed
479 TEST_F(BrowserPluginTest
, PartitionAttribute
) {
480 std::string html
= StringPrintf(kHTMLForPartitionedPluginObject
,
481 content::kBrowserPluginMimeType
);
482 LoadHTML(html
.c_str());
483 std::string partition_value
= ExecuteScriptAndReturnString(
484 "document.getElementById('browserplugin').partition");
485 EXPECT_STREQ("someid", partition_value
.c_str());
487 html
= StringPrintf(kHTMLForPartitionedPersistedPluginObject
,
488 content::kBrowserPluginMimeType
);
489 LoadHTML(html
.c_str());
490 partition_value
= ExecuteScriptAndReturnString(
491 "document.getElementById('browserplugin').partition");
492 EXPECT_STREQ("persist:someid", partition_value
.c_str());
494 // Verify that once HTML has defined a source and partition, we cannot change
495 // the partition anymore.
498 " document.getElementById('browserplugin').partition = 'foo';"
499 " document.title = 'success';"
500 "} catch (e) { document.title = e.message; }");
501 std::string title
= ExecuteScriptAndReturnString("document.title");
503 "The object has already navigated, so its partition cannot be changed.",
506 // Load a browser tag without 'src' defined.
507 html
= StringPrintf(kHTMLForSourcelessPluginObject
,
508 content::kBrowserPluginMimeType
);
509 LoadHTML(html
.c_str());
511 // Ensure we don't parse just "persist:" string and return exception.
514 " document.getElementById('browserplugin').partition = 'persist:';"
515 " document.title = 'success';"
516 "} catch (e) { document.title = e.message; }");
517 title
= ExecuteScriptAndReturnString("document.title");
518 EXPECT_STREQ("Invalid partition attribute.", title
.c_str());
521 // This test verifies that BrowserPlugin enters an error state when the
522 // partition attribute is invalid.
523 TEST_F(BrowserPluginTest
, InvalidPartition
) {
524 std::string html
= StringPrintf(kHTMLForInvalidPartitionedPluginObject
,
525 content::kBrowserPluginMimeType
);
526 LoadHTML(html
.c_str());
527 // Attempt to navigate with an invalid partition.
531 " document.getElementById('browserplugin').src = 'bar';"
532 " document.title = 'success';"
533 "} catch (e) { document.title = e.message; }");
534 std::string title
= ExecuteScriptAndReturnString("document.title");
535 EXPECT_STREQ("Invalid partition attribute.", title
.c_str());
536 // Verify that the 'src' attribute has not been updated.
537 EXPECT_EQ("", ExecuteScriptAndReturnString(
538 "document.getElementById('browserplugin').src"));
541 // Verify that the BrowserPlugin accepts changes to its src attribue after
542 // setting the partition to a valid value.
544 "document.getElementById('browserplugin').partition = 'persist:foo'");
545 ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
546 EXPECT_EQ("bar", ExecuteScriptAndReturnString(
547 "document.getElementById('browserplugin').src"));
548 // Verify that the BrowserPlugin does not 'deadlock': it can recover from
549 // the partition ID error state.
553 " document.getElementById('browserplugin').partition = 'persist:1337';"
554 " document.title = 'success';"
555 "} catch (e) { document.title = e.message; }");
556 std::string title
= ExecuteScriptAndReturnString("document.title");
558 "The object has already navigated, so its partition cannot be changed.",
560 ExecuteJavaScript("document.getElementById('browserplugin').src = '42'");
561 EXPECT_EQ("42", ExecuteScriptAndReturnString(
562 "document.getElementById('browserplugin').src"));
566 // Test to verify that after the first navigation, the partition attribute
567 // cannot be modified.
568 TEST_F(BrowserPluginTest
, ImmutableAttributesAfterNavigation
) {
569 std::string html
= StringPrintf(kHTMLForSourcelessPluginObject
,
570 content::kBrowserPluginMimeType
);
571 LoadHTML(html
.c_str());
574 "document.getElementById('browserplugin').partition = 'storage'");
575 std::string partition_value
= ExecuteScriptAndReturnString(
576 "document.getElementById('browserplugin').partition");
577 EXPECT_STREQ("storage", partition_value
.c_str());
579 std::string src_value
= ExecuteScriptAndReturnString(
580 "document.getElementById('browserplugin').src");
581 EXPECT_STREQ("", src_value
.c_str());
583 ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
585 const IPC::Message
* create_msg
=
586 browser_plugin_manager()->sink().GetUniqueMessageMatching(
587 BrowserPluginHostMsg_CreateGuest::ID
);
588 ASSERT_TRUE(create_msg
);
590 int create_instance_id
= 0;
591 BrowserPluginHostMsg_CreateGuest_Params params
;
592 BrowserPluginHostMsg_CreateGuest::Read(
596 EXPECT_STREQ("storage", params
.storage_partition_id
.c_str());
597 EXPECT_FALSE(params
.persist_storage
);
599 const IPC::Message
* msg
=
600 browser_plugin_manager()->sink().GetUniqueMessageMatching(
601 BrowserPluginHostMsg_NavigateGuest::ID
);
606 BrowserPluginHostMsg_NavigateGuest::Read(msg
, &instance_id
, &src
);
607 EXPECT_STREQ("bar", src
.c_str());
608 EXPECT_EQ(create_instance_id
, instance_id
);
611 // Setting the partition should throw an exception and the value should not
615 " document.getElementById('browserplugin').partition = 'someid';"
616 " document.title = 'success';"
617 "} catch (e) { document.title = e.message; }");
619 std::string title
= ExecuteScriptAndReturnString("document.title");
621 "The object has already navigated, so its partition cannot be changed.",
624 partition_value
= ExecuteScriptAndReturnString(
625 "document.getElementById('browserplugin').partition");
626 EXPECT_STREQ("storage", partition_value
.c_str());
629 // This test verifies that we can mutate the event listener vector
630 // within an event listener.
631 TEST_F(BrowserPluginTest
, RemoveEventListenerInEventListener
) {
632 const char* kAddEventListener
=
635 " url = JSON.parse(e.detail).url;"
636 " document.getElementById('browserplugin')."
637 " removeEventListener('-internal-loadcommit', nav);"
639 "document.getElementById('browserplugin')."
640 " addEventListener('-internal-loadcommit', nav);";
641 const char* kGoogleURL
= "http://www.google.com/";
642 const char* kGoogleNewsURL
= "http://news.google.com/";
643 const char* kGetProcessID
=
644 "document.getElementById('browserplugin').getProcessId()";
646 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
647 ExecuteJavaScript(kAddEventListener
);
648 // Grab the BrowserPlugin's instance ID from its resize message.
649 const IPC::Message
* msg
=
650 browser_plugin_manager()->sink().GetFirstMessageMatching(
651 BrowserPluginHostMsg_ResizeGuest::ID
);
654 BrowserPluginHostMsg_ResizeGuest_Params params
;
655 BrowserPluginHostMsg_ResizeGuest::Read(msg
, &instance_id
, ¶ms
);
657 MockBrowserPlugin
* browser_plugin
=
658 static_cast<MockBrowserPlugin
*>(
659 browser_plugin_manager()->GetBrowserPlugin(instance_id
));
660 ASSERT_TRUE(browser_plugin
);
663 BrowserPluginMsg_LoadCommit_Params navigate_params
;
664 navigate_params
.url
= GURL(kGoogleURL
);
665 navigate_params
.process_id
= 1337;
666 BrowserPluginMsg_LoadCommit
msg(0, instance_id
, navigate_params
);
667 browser_plugin
->OnMessageReceived(msg
);
668 EXPECT_EQ(kGoogleURL
, ExecuteScriptAndReturnString("url"));
669 EXPECT_EQ(1337, ExecuteScriptAndReturnInt(kGetProcessID
));
672 BrowserPluginMsg_LoadCommit_Params navigate_params
;
673 navigate_params
.url
= GURL(kGoogleNewsURL
);
674 navigate_params
.process_id
= 42;
675 BrowserPluginMsg_LoadCommit
msg(0, instance_id
, navigate_params
);
676 browser_plugin
->OnMessageReceived(msg
);
677 // The URL variable should not change because we've removed the event
679 EXPECT_EQ(kGoogleURL
, ExecuteScriptAndReturnString("url"));
680 EXPECT_EQ(42, ExecuteScriptAndReturnInt(kGetProcessID
));
684 // This test verifies that multiple event listeners fire that are registered
685 // on a single event type.
686 TEST_F(BrowserPluginTest
, MultipleEventListeners
) {
687 const char* kAddEventListener
=
695 "document.getElementById('browserplugin')."
696 " addEventListener('-internal-loadcommit', nava);"
697 "document.getElementById('browserplugin')."
698 " addEventListener('-internal-loadcommit', navb);";
699 const char* kGoogleURL
= "http://www.google.com/";
700 const char* kGetProcessID
=
701 "document.getElementById('browserplugin').getProcessId()";
703 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
704 ExecuteJavaScript(kAddEventListener
);
705 // Grab the BrowserPlugin's instance ID from its resize message.
706 const IPC::Message
* msg
=
707 browser_plugin_manager()->sink().GetFirstMessageMatching(
708 BrowserPluginHostMsg_ResizeGuest::ID
);
711 BrowserPluginHostMsg_ResizeGuest_Params params
;
712 BrowserPluginHostMsg_ResizeGuest::Read(msg
, &instance_id
, ¶ms
);
714 MockBrowserPlugin
* browser_plugin
=
715 static_cast<MockBrowserPlugin
*>(
716 browser_plugin_manager()->GetBrowserPlugin(instance_id
));
717 ASSERT_TRUE(browser_plugin
);
720 BrowserPluginMsg_LoadCommit_Params navigate_params
;
721 navigate_params
.url
= GURL(kGoogleURL
);
722 navigate_params
.process_id
= 1337;
723 BrowserPluginMsg_LoadCommit
msg(0, instance_id
, navigate_params
);
724 browser_plugin
->OnMessageReceived(msg
);
725 EXPECT_EQ(2, ExecuteScriptAndReturnInt("count"));
726 EXPECT_EQ(1337, ExecuteScriptAndReturnInt(kGetProcessID
));
730 TEST_F(BrowserPluginTest
, RemoveBrowserPluginOnExit
) {
731 LoadHTML(GetHTMLForBrowserPluginObject().c_str());
733 // Grab the BrowserPlugin's instance ID from its resize message.
736 const IPC::Message
* msg
=
737 browser_plugin_manager()->sink().GetFirstMessageMatching(
738 BrowserPluginHostMsg_ResizeGuest::ID
);
740 BrowserPluginHostMsg_ResizeGuest_Params params
;
741 BrowserPluginHostMsg_ResizeGuest::Read(msg
, &instance_id
, ¶ms
);
744 MockBrowserPlugin
* browser_plugin
=
745 static_cast<MockBrowserPlugin
*>(
746 browser_plugin_manager()->GetBrowserPlugin(instance_id
));
747 ASSERT_TRUE(browser_plugin
);
749 const char* kAddEventListener
=
750 "function exitListener(e) {"
751 " if (JSON.parse(e.detail).reason == 'killed') {"
752 " var bp = document.getElementById('browserplugin');"
753 " bp.parentNode.removeChild(bp);"
756 "document.getElementById('browserplugin')."
757 " addEventListener('-internal-exit', exitListener);";
759 ExecuteJavaScript(kAddEventListener
);
761 // Pretend that the guest has crashed.
762 BrowserPluginMsg_GuestGone
msg(
763 0, instance_id
, 0, base::TERMINATION_STATUS_PROCESS_WAS_KILLED
);
764 browser_plugin
->OnMessageReceived(msg
);
766 ProcessPendingMessages();
768 EXPECT_EQ(NULL
, browser_plugin_manager()->GetBrowserPlugin(instance_id
));
771 TEST_F(BrowserPluginTest
, AutoSizeAttributes
) {
772 std::string html
= StringPrintf(kHTMLForSourcelessPluginObject
,
773 content::kBrowserPluginMimeType
);
774 LoadHTML(html
.c_str());
775 const char* kSetAutoSizeParametersAndNavigate
=
776 "var browserplugin = document.getElementById('browserplugin');"
777 "browserplugin.autoSize = true;"
778 "browserplugin.minWidth = 42;"
779 "browserplugin.minHeight = 43;"
780 "browserplugin.maxWidth = 1337;"
781 "browserplugin.maxHeight = 1338;"
782 "browserplugin.src = 'foobar';";
783 const char* kDisableAutoSize
=
784 "document.getElementById('browserplugin').autoSize = false;";
787 // Set some autosize parameters before navigating then navigate.
788 // Verify that the BrowserPluginHostMsg_CreateGuest message contains
789 // the correct autosize parameters.
790 ExecuteJavaScript(kSetAutoSizeParametersAndNavigate
);
791 ProcessPendingMessages();
793 const IPC::Message
* create_msg
=
794 browser_plugin_manager()->sink().GetUniqueMessageMatching(
795 BrowserPluginHostMsg_CreateGuest::ID
);
796 ASSERT_TRUE(create_msg
);
798 BrowserPluginHostMsg_CreateGuest_Params params
;
799 BrowserPluginHostMsg_CreateGuest::Read(
803 EXPECT_TRUE(params
.auto_size_params
.enable
);
804 EXPECT_EQ(42, params
.auto_size_params
.min_size
.width());
805 EXPECT_EQ(43, params
.auto_size_params
.min_size
.height());
806 EXPECT_EQ(1337, params
.auto_size_params
.max_size
.width());
807 EXPECT_EQ(1338, params
.auto_size_params
.max_size
.height());
809 // Verify that we are waiting for the browser process to grab the new
811 MockBrowserPlugin
* browser_plugin
=
812 static_cast<MockBrowserPlugin
*>(
813 browser_plugin_manager()->GetBrowserPlugin(instance_id
));
814 EXPECT_TRUE(browser_plugin
->pending_damage_buffer_
);
815 // Disable autosize. AutoSize state will not be sent to the guest until
816 // the guest has responded to the last resize request.
817 ExecuteJavaScript(kDisableAutoSize
);
818 ProcessPendingMessages();
820 const IPC::Message
* auto_size_msg
=
821 browser_plugin_manager()->sink().GetUniqueMessageMatching(
822 BrowserPluginHostMsg_SetAutoSize::ID
);
823 EXPECT_FALSE(auto_size_msg
);
825 // Send the BrowserPlugin an UpdateRect equal to its |max_size| with
826 // the same damage buffer.
827 BrowserPluginMsg_UpdateRect_Params update_rect_params
;
828 update_rect_params
.damage_buffer_identifier
=
829 #if defined(OS_MACOSX)
830 browser_plugin
->pending_damage_buffer_
->id();
832 browser_plugin
->pending_damage_buffer_
->handle();
834 update_rect_params
.view_size
= gfx::Size(1337, 1338);
835 update_rect_params
.scale_factor
= 1.0f
;
836 update_rect_params
.is_resize_ack
= true;
837 BrowserPluginMsg_UpdateRect
msg(0, instance_id
, 0, update_rect_params
);
838 browser_plugin
->OnMessageReceived(msg
);
840 // Verify that the autosize state has been updated.
842 const IPC::Message
* auto_size_msg
=
843 browser_plugin_manager()->sink().GetUniqueMessageMatching(
844 BrowserPluginHostMsg_UpdateRect_ACK::ID
);
845 ASSERT_TRUE(auto_size_msg
);
849 BrowserPluginHostMsg_AutoSize_Params auto_size_params
;
850 BrowserPluginHostMsg_ResizeGuest_Params resize_params
;
851 BrowserPluginHostMsg_UpdateRect_ACK::Read(auto_size_msg
,
856 EXPECT_FALSE(auto_size_params
.enable
);
857 EXPECT_EQ(42, auto_size_params
.min_size
.width());
858 EXPECT_EQ(43, auto_size_params
.min_size
.height());
859 EXPECT_EQ(1337, auto_size_params
.max_size
.width());
860 EXPECT_EQ(1338, auto_size_params
.max_size
.height());
864 } // namespace content