[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / content / renderer / browser_plugin / browser_plugin_browsertest.cc
blob0495ee7be987c080617bf0759fbbf96e079565d8
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"
24 namespace {
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);
49 } // namespace
51 namespace content {
53 // Test factory for creating test instances of BrowserPluginManager.
54 class TestBrowserPluginManagerFactory : public BrowserPluginManagerFactory {
55 public:
56 virtual MockBrowserPluginManager* CreateBrowserPluginManager(
57 RenderViewImpl* render_view) OVERRIDE {
58 return new MockBrowserPluginManager(render_view);
61 // Singleton getter.
62 static TestBrowserPluginManagerFactory* GetInstance() {
63 return Singleton<TestBrowserPluginManagerFactory>::get();
66 protected:
67 TestBrowserPluginManagerFactory() {}
68 virtual ~TestBrowserPluginManagerFactory() {}
70 private:
71 // For Singleton.
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);
107 return str.get();
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())
115 return 0;
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.
130 int instance_id = 0;
132 const IPC::Message* msg =
133 browser_plugin_manager()->sink().GetUniqueMessageMatching(
134 BrowserPluginHostMsg_ResizeGuest::ID);
135 ASSERT_TRUE(msg);
136 BrowserPluginHostMsg_ResizeGuest_Params params;
137 BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
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();
155 #else
156 browser_plugin->pending_damage_buffer_->handle();
157 #endif
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
170 // src attribute.
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);
181 ASSERT_TRUE(msg);
183 int instance_id = 0;
184 std::string src;
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);
204 ASSERT_TRUE(msg);
206 int instance_id = 0;
207 std::string src;
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());
219 int instance_id = 0;
221 // Ensure we get a NavigateGuest on the initial navigation and grab the
222 // BrowserPlugin's instance_id from there.
223 std::string src;
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
236 // buffer.
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();
249 #else
250 browser_plugin->pending_damage_buffer_->handle();
251 #endif
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
269 // guest.
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);
274 ASSERT_TRUE(msg);
275 BrowserPluginHostMsg_ResizeGuest_Params params;
276 BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
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();
292 #else
293 browser_plugin->pending_damage_buffer_->handle();
294 #endif
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();
311 #else
312 browser_plugin->pending_damage_buffer_->handle();
313 #endif
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.
326 int instance_id = 0;
328 const IPC::Message* msg =
329 browser_plugin_manager()->sink().GetFirstMessageMatching(
330 BrowserPluginHostMsg_ResizeGuest::ID);
331 ASSERT_TRUE(msg);
332 BrowserPluginHostMsg_ResizeGuest_Params params;
333 BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
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(),
343 cursor_info);
344 EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
345 BrowserPluginHostMsg_HandleInputEvent::ID));
346 browser_plugin_manager()->sink().ClearMessages();
348 const char* kAddEventListener =
349 "var msg;"
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(),
380 cursor_info);
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 =
398 "var url;"
399 "function nav(e) {"
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);
420 ASSERT_TRUE(msg);
421 int instance_id = 0;
422 BrowserPluginHostMsg_ResizeGuest_Params params;
423 BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
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
450 // listener.
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
478 // correctly.
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.
496 ExecuteJavaScript(
497 "try {"
498 " document.getElementById('browserplugin').partition = 'foo';"
499 " document.title = 'success';"
500 "} catch (e) { document.title = e.message; }");
501 std::string title = ExecuteScriptAndReturnString("document.title");
502 EXPECT_STREQ(
503 "The object has already navigated, so its partition cannot be changed.",
504 title.c_str());
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.
512 ExecuteJavaScript(
513 "try {"
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.
529 ExecuteJavaScript(
530 "try {"
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.
543 ExecuteJavaScript(
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.
551 ExecuteJavaScript(
552 "try {"
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");
557 EXPECT_STREQ(
558 "The object has already navigated, so its partition cannot be changed.",
559 title.c_str());
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());
573 ExecuteJavaScript(
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(
593 create_msg,
594 &create_instance_id,
595 &params);
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);
602 ASSERT_TRUE(msg);
604 int instance_id = 0;
605 std::string src;
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
612 // change.
613 ExecuteJavaScript(
614 "try {"
615 " document.getElementById('browserplugin').partition = 'someid';"
616 " document.title = 'success';"
617 "} catch (e) { document.title = e.message; }");
619 std::string title = ExecuteScriptAndReturnString("document.title");
620 EXPECT_STREQ(
621 "The object has already navigated, so its partition cannot be changed.",
622 title.c_str());
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 =
633 "var url;"
634 "function nav(e) {"
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);
652 ASSERT_TRUE(msg);
653 int instance_id = 0;
654 BrowserPluginHostMsg_ResizeGuest_Params params;
655 BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
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
678 // listener.
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 =
688 "var count = 0;"
689 "function nava(u) {"
690 " count++;"
692 "function navb(u) {"
693 " count++;"
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);
709 ASSERT_TRUE(msg);
710 int instance_id = 0;
711 BrowserPluginHostMsg_ResizeGuest_Params params;
712 BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
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.
734 int instance_id = 0;
736 const IPC::Message* msg =
737 browser_plugin_manager()->sink().GetFirstMessageMatching(
738 BrowserPluginHostMsg_ResizeGuest::ID);
739 ASSERT_TRUE(msg);
740 BrowserPluginHostMsg_ResizeGuest_Params params;
741 BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
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);"
754 " }"
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;";
786 int instance_id = 0;
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(
800 create_msg,
801 &instance_id,
802 &params);
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
810 // damage buffer.
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();
831 #else
832 browser_plugin->pending_damage_buffer_->handle();
833 #endif
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);
847 int instance_id = 0;
848 int message_id = 0;
849 BrowserPluginHostMsg_AutoSize_Params auto_size_params;
850 BrowserPluginHostMsg_ResizeGuest_Params resize_params;
851 BrowserPluginHostMsg_UpdateRect_ACK::Read(auto_size_msg,
852 &instance_id,
853 &message_id,
854 &auto_size_params,
855 &resize_params);
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