- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / browser_plugin / browser_plugin_browsertest.cc
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.
4
5 #include "content/renderer/browser_plugin/browser_plugin_browsertest.h"
6
7 #include "base/files/file_path.h"
8 #include "base/memory/singleton.h"
9 #include "base/path_service.h"
10 #include "base/pickle.h"
11 #include "content/public/common/content_constants.h"
12 #include "content/renderer/browser_plugin/browser_plugin.h"
13 #include "content/renderer/browser_plugin/browser_plugin_manager_factory.h"
14 #include "content/renderer/browser_plugin/mock_browser_plugin.h"
15 #include "content/renderer/browser_plugin/mock_browser_plugin_manager.h"
16 #include "content/renderer/render_thread_impl.h"
17 #include "content/renderer/renderer_webkitplatformsupport_impl.h"
18 #include "skia/ext/platform_canvas.h"
19 #include "third_party/WebKit/public/web/WebCursorInfo.h"
20 #include "third_party/WebKit/public/web/WebInputEvent.h"
21 #include "third_party/WebKit/public/web/WebScriptSource.h"
22
23 namespace {
24 const char kHTMLForBrowserPluginObject[] =
25     "<object id='browserplugin' width='640px' height='480px'"
26     " src='foo' type='%s'>";
27
28 const char kHTMLForBrowserPluginWithAllAttributes[] =
29     "<object id='browserplugin' width='640' height='480' type='%s'"
30     " autosize maxheight='600' maxwidth='800' minheight='240'"
31     " minwidth='320' name='Jim' partition='someid' src='foo'>";
32
33 const char kHTMLForSourcelessPluginObject[] =
34     "<object id='browserplugin' width='640px' height='480px' type='%s'>";
35
36 const char kHTMLForPartitionedPluginObject[] =
37     "<object id='browserplugin' width='640px' height='480px'"
38     "  src='foo' type='%s' partition='someid'>";
39
40 const char kHTMLForInvalidPartitionedPluginObject[] =
41     "<object id='browserplugin' width='640px' height='480px'"
42     "  type='%s' partition='persist:'>";
43
44 const char kHTMLForPartitionedPersistedPluginObject[] =
45     "<object id='browserplugin' width='640px' height='480px'"
46     "  src='foo' type='%s' partition='persist:someid'>";
47
48 std::string GetHTMLForBrowserPluginObject() {
49   return base::StringPrintf(kHTMLForBrowserPluginObject,
50                             content::kBrowserPluginMimeType);
51 }
52
53 }  // namespace
54
55 namespace content {
56
57 class TestContentRendererClient : public ContentRendererClient {
58  public:
59   TestContentRendererClient() : ContentRendererClient() {
60   }
61   virtual ~TestContentRendererClient() {
62   }
63   virtual bool AllowBrowserPlugin(
64       WebKit::WebPluginContainer* container) OVERRIDE {
65     // Allow BrowserPlugin for tests.
66     return true;
67   }
68 };
69
70 // Test factory for creating test instances of BrowserPluginManager.
71 class TestBrowserPluginManagerFactory : public BrowserPluginManagerFactory {
72  public:
73   virtual MockBrowserPluginManager* CreateBrowserPluginManager(
74       RenderViewImpl* render_view) OVERRIDE {
75     return new MockBrowserPluginManager(render_view);
76   }
77
78   // Singleton getter.
79   static TestBrowserPluginManagerFactory* GetInstance() {
80     return Singleton<TestBrowserPluginManagerFactory>::get();
81   }
82
83  protected:
84   TestBrowserPluginManagerFactory() {}
85   virtual ~TestBrowserPluginManagerFactory() {}
86
87  private:
88   // For Singleton.
89   friend struct DefaultSingletonTraits<TestBrowserPluginManagerFactory>;
90
91   DISALLOW_COPY_AND_ASSIGN(TestBrowserPluginManagerFactory);
92 };
93
94 BrowserPluginTest::BrowserPluginTest() {}
95
96 BrowserPluginTest::~BrowserPluginTest() {}
97
98 void BrowserPluginTest::SetUp() {
99   test_content_renderer_client_.reset(new TestContentRendererClient);
100   SetRendererClientForTesting(test_content_renderer_client_.get());
101   BrowserPluginManager::set_factory_for_testing(
102       TestBrowserPluginManagerFactory::GetInstance());
103   content::RenderViewTest::SetUp();
104 }
105
106 void BrowserPluginTest::TearDown() {
107   BrowserPluginManager::set_factory_for_testing(
108       TestBrowserPluginManagerFactory::GetInstance());
109   content::RenderViewTest::TearDown();
110   test_content_renderer_client_.reset();
111 }
112
113 std::string BrowserPluginTest::ExecuteScriptAndReturnString(
114     const std::string& script) {
115   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
116   v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
117       WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script.c_str())));
118   if (value.IsEmpty() || !value->IsString())
119     return std::string();
120
121   v8::Local<v8::String> v8_str = value->ToString();
122   int length = v8_str->Utf8Length() + 1;
123   scoped_ptr<char[]> str(new char[length]);
124   v8_str->WriteUtf8(str.get(), length);
125   return str.get();
126 }
127
128 int BrowserPluginTest::ExecuteScriptAndReturnInt(
129     const std::string& script) {
130   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
131   v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
132       WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script.c_str())));
133   if (value.IsEmpty() || !value->IsInt32())
134     return 0;
135
136   return value->Int32Value();
137 }
138
139 // A return value of false means that a value was not present. The return value
140 // of the script is stored in |result|
141 bool BrowserPluginTest::ExecuteScriptAndReturnBool(
142     const std::string& script, bool* result) {
143   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
144   v8::Handle<v8::Value> value = GetMainFrame()->executeScriptAndReturnValue(
145       WebKit::WebScriptSource(WebKit::WebString::fromUTF8(script.c_str())));
146   if (value.IsEmpty() || !value->IsBoolean())
147     return false;
148
149   *result = value->BooleanValue();
150   return true;
151 }
152
153 MockBrowserPlugin* BrowserPluginTest::GetCurrentPlugin() {
154   BrowserPluginHostMsg_Attach_Params params;
155   return GetCurrentPluginWithAttachParams(&params);
156 }
157
158 MockBrowserPlugin* BrowserPluginTest::GetCurrentPluginWithAttachParams(
159     BrowserPluginHostMsg_Attach_Params* params) {
160   int instance_id = 0;
161   const IPC::Message* msg =
162       browser_plugin_manager()->sink().GetUniqueMessageMatching(
163           BrowserPluginHostMsg_Attach::ID);
164   if (!msg)
165     return NULL;
166
167   PickleIterator iter(*msg);
168   if (!iter.ReadInt(&instance_id))
169     return NULL;
170
171   if (!IPC::ParamTraits<BrowserPluginHostMsg_Attach_Params>::Read(
172       msg, &iter, params))
173     return NULL;
174
175   MockBrowserPlugin* browser_plugin = static_cast<MockBrowserPlugin*>(
176       browser_plugin_manager()->GetBrowserPlugin(instance_id));
177
178   BrowserPluginMsg_Attach_ACK_Params attach_ack_params;
179   browser_plugin->OnAttachACK(instance_id, attach_ack_params);
180
181   return browser_plugin;
182 }
183
184 // This test verifies that an initial resize occurs when we instantiate the
185 // browser plugin. This test also verifies that the browser plugin is waiting
186 // for a BrowserPluginMsg_UpdateRect in response. We issue an UpdateRect, and
187 // we observe an UpdateRect_ACK, with the |pending_damage_buffer_| reset,
188 // indiciating that the BrowserPlugin is not waiting for any more UpdateRects to
189 // satisfy its resize request.
190 TEST_F(BrowserPluginTest, InitialResize) {
191   LoadHTML(GetHTMLForBrowserPluginObject().c_str());
192   // Verify that the information in Attach is correct.
193   BrowserPluginHostMsg_Attach_Params params;
194   MockBrowserPlugin* browser_plugin = GetCurrentPluginWithAttachParams(&params);
195
196   EXPECT_EQ(640, params.resize_guest_params.view_rect.width());
197   EXPECT_EQ(480, params.resize_guest_params.view_rect.height());
198   ASSERT_TRUE(browser_plugin);
199   // Now the browser plugin is expecting a UpdateRect resize.
200   int instance_id = browser_plugin->guest_instance_id();
201   EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
202
203   // Send the BrowserPlugin an UpdateRect equal to its container size with
204   // the same damage buffer. That should clear |pending_damage_buffer_|.
205   BrowserPluginMsg_UpdateRect_Params update_rect_params;
206   update_rect_params.damage_buffer_sequence_id =
207       browser_plugin->damage_buffer_sequence_id_;
208   update_rect_params.view_size = gfx::Size(640, 480);
209   update_rect_params.scale_factor = 1.0f;
210   update_rect_params.is_resize_ack = true;
211   update_rect_params.needs_ack = true;
212   BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
213   browser_plugin->OnMessageReceived(msg);
214   EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
215 }
216
217 // This test verifies that all attributes (present at the time of writing) are
218 // parsed on initialization. However, this test does minimal checking of
219 // correct behavior.
220 TEST_F(BrowserPluginTest, ParseAllAttributes) {
221   std::string html = base::StringPrintf(kHTMLForBrowserPluginWithAllAttributes,
222                                         content::kBrowserPluginMimeType);
223   LoadHTML(html.c_str());
224   bool result;
225   bool has_value = ExecuteScriptAndReturnBool(
226       "document.getElementById('browserplugin').autosize", &result);
227   EXPECT_TRUE(has_value);
228   EXPECT_TRUE(result);
229   int maxHeight = ExecuteScriptAndReturnInt(
230       "document.getElementById('browserplugin').maxheight");
231   EXPECT_EQ(600, maxHeight);
232   int maxWidth = ExecuteScriptAndReturnInt(
233       "document.getElementById('browserplugin').maxwidth");
234   EXPECT_EQ(800, maxWidth);
235   int minHeight = ExecuteScriptAndReturnInt(
236       "document.getElementById('browserplugin').minheight");
237   EXPECT_EQ(240, minHeight);
238   int minWidth = ExecuteScriptAndReturnInt(
239       "document.getElementById('browserplugin').minwidth");
240   EXPECT_EQ(320, minWidth);
241   std::string name = ExecuteScriptAndReturnString(
242       "document.getElementById('browserplugin').name");
243   EXPECT_STREQ("Jim", name.c_str());
244   std::string partition = ExecuteScriptAndReturnString(
245       "document.getElementById('browserplugin').partition");
246   EXPECT_STREQ("someid", partition.c_str());
247   std::string src = ExecuteScriptAndReturnString(
248       "document.getElementById('browserplugin').src");
249   EXPECT_STREQ("foo", src.c_str());
250 }
251
252 // Verify that the src attribute on the browser plugin works as expected.
253 TEST_F(BrowserPluginTest, SrcAttribute) {
254   LoadHTML(GetHTMLForBrowserPluginObject().c_str());
255   // Verify that we're reporting the correct URL to navigate to based on the
256   // src attribute.
257   {
258     BrowserPluginHostMsg_Attach_Params params;
259     MockBrowserPlugin* browser_plugin =
260         GetCurrentPluginWithAttachParams(&params);
261     ASSERT_TRUE(browser_plugin);
262     EXPECT_EQ("foo", params.src);
263   }
264
265   browser_plugin_manager()->sink().ClearMessages();
266   // Navigate to bar and observe the associated
267   // BrowserPluginHostMsg_NavigateGuest message.
268   // Verify that the src attribute is updated as well.
269   ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
270   {
271     // Verify that we do not get a Attach on subsequent navigations.
272     const IPC::Message* create_msg =
273         browser_plugin_manager()->sink().GetUniqueMessageMatching(
274             BrowserPluginHostMsg_Attach::ID);
275     ASSERT_FALSE(create_msg);
276
277     const IPC::Message* msg =
278         browser_plugin_manager()->sink().GetUniqueMessageMatching(
279             BrowserPluginHostMsg_NavigateGuest::ID);
280     ASSERT_TRUE(msg);
281
282     int instance_id = 0;
283     std::string src;
284     BrowserPluginHostMsg_NavigateGuest::Read(msg, &instance_id, &src);
285     EXPECT_EQ("bar", src);
286     std::string src_value =
287         ExecuteScriptAndReturnString(
288             "document.getElementById('browserplugin').src");
289     EXPECT_EQ("bar", src_value);
290   }
291 }
292
293 TEST_F(BrowserPluginTest, ResizeFlowControl) {
294   LoadHTML(GetHTMLForBrowserPluginObject().c_str());
295   MockBrowserPlugin* browser_plugin = GetCurrentPlugin();
296   ASSERT_TRUE(browser_plugin);
297   int instance_id = browser_plugin->guest_instance_id();
298   EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
299   // Send an UpdateRect to the BrowserPlugin to make it use the pending damage
300   // buffer.
301   {
302     // We send a stale UpdateRect to the BrowserPlugin.
303     BrowserPluginMsg_UpdateRect_Params update_rect_params;
304     update_rect_params.view_size = gfx::Size(640, 480);
305     update_rect_params.scale_factor = 1.0f;
306     update_rect_params.is_resize_ack = true;
307     update_rect_params.needs_ack = true;
308     // By sending |damage_buffer_sequence_id| back to BrowserPlugin on
309     // UpdateRect, then the BrowserPlugin knows that the browser process has
310     // received and has begun to use the |pending_damage_buffer_|.
311     update_rect_params.damage_buffer_sequence_id =
312         browser_plugin->damage_buffer_sequence_id_;
313     BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
314     browser_plugin->OnMessageReceived(msg);
315     EXPECT_EQ(NULL, browser_plugin->pending_damage_buffer_.get());
316   }
317
318   browser_plugin_manager()->sink().ClearMessages();
319
320   // Resize the browser plugin three times.
321   ExecuteJavaScript("document.getElementById('browserplugin').width = '641px'");
322   ProcessPendingMessages();
323   ExecuteJavaScript("document.getElementById('browserplugin').width = '642px'");
324   ProcessPendingMessages();
325   ExecuteJavaScript("document.getElementById('browserplugin').width = '643px'");
326   ProcessPendingMessages();
327
328   // Expect to see one resize messsage in the sink. BrowserPlugin will not issue
329   // subsequent resize requests until the first request is satisfied by the
330   // guest. The rest of the messages could be
331   // BrowserPluginHostMsg_UpdateGeometry msgs.
332   EXPECT_LE(1u, browser_plugin_manager()->sink().message_count());
333   for (size_t i = 0; i < browser_plugin_manager()->sink().message_count();
334        ++i) {
335     const IPC::Message* msg = browser_plugin_manager()->sink().GetMessageAt(i);
336     if (msg->type() != BrowserPluginHostMsg_ResizeGuest::ID)
337       EXPECT_EQ(msg->type(), BrowserPluginHostMsg_UpdateGeometry::ID);
338   }
339   const IPC::Message* msg =
340       browser_plugin_manager()->sink().GetUniqueMessageMatching(
341           BrowserPluginHostMsg_ResizeGuest::ID);
342   ASSERT_TRUE(msg);
343   BrowserPluginHostMsg_ResizeGuest_Params params;
344   BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
345   EXPECT_EQ(641, params.view_rect.width());
346   EXPECT_EQ(480, params.view_rect.height());
347   // This indicates that the BrowserPlugin has sent out a previous resize
348   // request but has not yet received an UpdateRect for that request.
349   EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
350
351   {
352     // We send a stale UpdateRect to the BrowserPlugin.
353     BrowserPluginMsg_UpdateRect_Params update_rect_params;
354     update_rect_params.view_size = gfx::Size(641, 480);
355     update_rect_params.scale_factor = 1.0f;
356     update_rect_params.is_resize_ack = true;
357     update_rect_params.needs_ack = true;
358     update_rect_params.damage_buffer_sequence_id =
359         browser_plugin->damage_buffer_sequence_id_;
360     BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
361     browser_plugin->OnMessageReceived(msg);
362     // This tells us that the BrowserPlugin is still expecting another
363     // UpdateRect with the most recent size.
364     EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
365   }
366   // Send the BrowserPlugin another UpdateRect, but this time with a size
367   // that matches the size of the container.
368   {
369     BrowserPluginMsg_UpdateRect_Params update_rect_params;
370     update_rect_params.view_size = gfx::Size(643, 480);
371     update_rect_params.scale_factor = 1.0f;
372     update_rect_params.is_resize_ack = true;
373     update_rect_params.needs_ack = true;
374     update_rect_params.damage_buffer_sequence_id =
375         browser_plugin->damage_buffer_sequence_id_;
376     BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
377     browser_plugin->OnMessageReceived(msg);
378     // The BrowserPlugin has finally received an UpdateRect that satisifes
379     // its current size, and so it is happy.
380     EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
381   }
382 }
383
384 TEST_F(BrowserPluginTest, RemovePlugin) {
385   LoadHTML(GetHTMLForBrowserPluginObject().c_str());
386   EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
387       BrowserPluginHostMsg_PluginDestroyed::ID));
388   ExecuteJavaScript("x = document.getElementById('browserplugin'); "
389                     "x.parentNode.removeChild(x);");
390   ProcessPendingMessages();
391   EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
392       BrowserPluginHostMsg_PluginDestroyed::ID));
393 }
394
395 // This test verifies that PluginDestroyed messages do not get sent from a
396 // BrowserPlugin that has never navigated.
397 TEST_F(BrowserPluginTest, RemovePluginBeforeNavigation) {
398   std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
399                                         content::kBrowserPluginMimeType);
400   LoadHTML(html.c_str());
401   EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
402       BrowserPluginHostMsg_PluginDestroyed::ID));
403   ExecuteJavaScript("x = document.getElementById('browserplugin'); "
404                     "x.parentNode.removeChild(x);");
405   ProcessPendingMessages();
406   EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
407       BrowserPluginHostMsg_PluginDestroyed::ID));
408 }
409
410 // Verify that the 'partition' attribute on the browser plugin is parsed
411 // correctly.
412 TEST_F(BrowserPluginTest, PartitionAttribute) {
413   std::string html = base::StringPrintf(kHTMLForPartitionedPluginObject,
414                                         content::kBrowserPluginMimeType);
415   LoadHTML(html.c_str());
416   std::string partition_value = ExecuteScriptAndReturnString(
417       "document.getElementById('browserplugin').partition");
418   EXPECT_STREQ("someid", partition_value.c_str());
419
420   html = base::StringPrintf(kHTMLForPartitionedPersistedPluginObject,
421                             content::kBrowserPluginMimeType);
422   LoadHTML(html.c_str());
423   partition_value = ExecuteScriptAndReturnString(
424       "document.getElementById('browserplugin').partition");
425   EXPECT_STREQ("persist:someid", partition_value.c_str());
426
427   // Verify that once HTML has defined a source and partition, we cannot change
428   // the partition anymore.
429   ExecuteJavaScript(
430       "try {"
431       "  document.getElementById('browserplugin').partition = 'foo';"
432       "  document.title = 'success';"
433       "} catch (e) { document.title = e.message; }");
434   std::string title = ExecuteScriptAndReturnString("document.title");
435   EXPECT_STREQ(
436       "The object has already navigated, so its partition cannot be changed.",
437       title.c_str());
438
439   // Load a browser tag without 'src' defined.
440   html = base::StringPrintf(kHTMLForSourcelessPluginObject,
441                             content::kBrowserPluginMimeType);
442   LoadHTML(html.c_str());
443
444   // Ensure we don't parse just "persist:" string and return exception.
445   ExecuteJavaScript(
446       "try {"
447       "  document.getElementById('browserplugin').partition = 'persist:';"
448       "  document.title = 'success';"
449       "} catch (e) { document.title = e.message; }");
450   title = ExecuteScriptAndReturnString("document.title");
451   EXPECT_STREQ("Invalid partition attribute.", title.c_str());
452 }
453
454 // This test verifies that BrowserPlugin enters an error state when the
455 // partition attribute is invalid.
456 TEST_F(BrowserPluginTest, InvalidPartition) {
457   std::string html = base::StringPrintf(kHTMLForInvalidPartitionedPluginObject,
458                                         content::kBrowserPluginMimeType);
459   LoadHTML(html.c_str());
460   // Attempt to navigate with an invalid partition.
461   {
462     ExecuteJavaScript(
463         "try {"
464         "  document.getElementById('browserplugin').src = 'bar';"
465         "  document.title = 'success';"
466         "} catch (e) { document.title = e.message; }");
467     std::string title = ExecuteScriptAndReturnString("document.title");
468     EXPECT_STREQ("Invalid partition attribute.", title.c_str());
469     // Verify that the 'src' attribute has not been updated.
470     EXPECT_EQ("", ExecuteScriptAndReturnString(
471         "document.getElementById('browserplugin').src"));
472   }
473
474   // Verify that the BrowserPlugin accepts changes to its src attribue after
475   // setting the partition to a valid value.
476   ExecuteJavaScript(
477       "document.getElementById('browserplugin').partition = 'persist:foo'");
478   ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
479   EXPECT_EQ("bar", ExecuteScriptAndReturnString(
480       "document.getElementById('browserplugin').src"));
481   ProcessPendingMessages();
482   // Verify that the BrowserPlugin does not 'deadlock': it can recover from
483   // the partition ID error state.
484   {
485     ExecuteJavaScript(
486         "try {"
487         "  document.getElementById('browserplugin').partition = 'persist:1337';"
488         "  document.title = 'success';"
489         "} catch (e) { document.title = e.message; }");
490     std::string title = ExecuteScriptAndReturnString("document.title");
491     EXPECT_STREQ(
492         "The object has already navigated, so its partition cannot be changed.",
493         title.c_str());
494     ExecuteJavaScript("document.getElementById('browserplugin').src = '42'");
495     EXPECT_EQ("42", ExecuteScriptAndReturnString(
496         "document.getElementById('browserplugin').src"));
497   }
498 }
499
500 // Test to verify that after the first navigation, the partition attribute
501 // cannot be modified.
502 TEST_F(BrowserPluginTest, ImmutableAttributesAfterNavigation) {
503   std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
504                                         content::kBrowserPluginMimeType);
505   LoadHTML(html.c_str());
506
507   ExecuteJavaScript(
508       "document.getElementById('browserplugin').partition = 'storage'");
509   std::string partition_value = ExecuteScriptAndReturnString(
510       "document.getElementById('browserplugin').partition");
511   EXPECT_STREQ("storage", partition_value.c_str());
512
513   std::string src_value = ExecuteScriptAndReturnString(
514       "document.getElementById('browserplugin').src");
515   EXPECT_STREQ("", src_value.c_str());
516
517   ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
518   ProcessPendingMessages();
519   {
520     BrowserPluginHostMsg_Attach_Params params;
521     MockBrowserPlugin* browser_plugin =
522         GetCurrentPluginWithAttachParams(&params);
523     ASSERT_TRUE(browser_plugin);
524
525     EXPECT_STREQ("storage", params.storage_partition_id.c_str());
526     EXPECT_FALSE(params.persist_storage);
527     EXPECT_STREQ("bar", params.src.c_str());
528   }
529
530   // Setting the partition should throw an exception and the value should not
531   // change.
532   ExecuteJavaScript(
533       "try {"
534       "  document.getElementById('browserplugin').partition = 'someid';"
535       "  document.title = 'success';"
536       "} catch (e) { document.title = e.message; }");
537
538   std::string title = ExecuteScriptAndReturnString("document.title");
539   EXPECT_STREQ(
540       "The object has already navigated, so its partition cannot be changed.",
541       title.c_str());
542
543   partition_value = ExecuteScriptAndReturnString(
544       "document.getElementById('browserplugin').partition");
545   EXPECT_STREQ("storage", partition_value.c_str());
546 }
547
548 TEST_F(BrowserPluginTest, AutoSizeAttributes) {
549   std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
550                                         content::kBrowserPluginMimeType);
551   LoadHTML(html.c_str());
552   const char* kSetAutoSizeParametersAndNavigate =
553     "var browserplugin = document.getElementById('browserplugin');"
554     "browserplugin.autosize = true;"
555     "browserplugin.minwidth = 42;"
556     "browserplugin.minheight = 43;"
557     "browserplugin.maxwidth = 1337;"
558     "browserplugin.maxheight = 1338;"
559     "browserplugin.src = 'foobar';";
560   const char* kDisableAutoSize =
561     "document.getElementById('browserplugin').removeAttribute('autosize');";
562
563   int instance_id = 0;
564   // Set some autosize parameters before navigating then navigate.
565   // Verify that the BrowserPluginHostMsg_Attach message contains
566   // the correct autosize parameters.
567   ExecuteJavaScript(kSetAutoSizeParametersAndNavigate);
568   ProcessPendingMessages();
569
570   BrowserPluginHostMsg_Attach_Params params;
571   MockBrowserPlugin* browser_plugin =
572       GetCurrentPluginWithAttachParams(&params);
573   ASSERT_TRUE(browser_plugin);
574
575   EXPECT_TRUE(params.auto_size_params.enable);
576   EXPECT_EQ(42, params.auto_size_params.min_size.width());
577   EXPECT_EQ(43, params.auto_size_params.min_size.height());
578   EXPECT_EQ(1337, params.auto_size_params.max_size.width());
579   EXPECT_EQ(1338, params.auto_size_params.max_size.height());
580
581   // Verify that we are waiting for the browser process to grab the new
582   // damage buffer.
583   EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
584   // Disable autosize. AutoSize state will not be sent to the guest until
585   // the guest has responded to the last resize request.
586   ExecuteJavaScript(kDisableAutoSize);
587   ProcessPendingMessages();
588
589   const IPC::Message* auto_size_msg =
590   browser_plugin_manager()->sink().GetUniqueMessageMatching(
591       BrowserPluginHostMsg_SetAutoSize::ID);
592   EXPECT_FALSE(auto_size_msg);
593
594   // Send the BrowserPlugin an UpdateRect equal to its |max_size| with
595   // the same damage buffer.
596   BrowserPluginMsg_UpdateRect_Params update_rect_params;
597   update_rect_params.damage_buffer_sequence_id =
598       browser_plugin->damage_buffer_sequence_id_;
599   update_rect_params.view_size = gfx::Size(1337, 1338);
600   update_rect_params.scale_factor = 1.0f;
601   update_rect_params.is_resize_ack = true;
602   update_rect_params.needs_ack = true;
603   BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
604   browser_plugin->OnMessageReceived(msg);
605
606   // Verify that the autosize state has been updated.
607   {
608     const IPC::Message* auto_size_msg =
609     browser_plugin_manager()->sink().GetUniqueMessageMatching(
610         BrowserPluginHostMsg_UpdateRect_ACK::ID);
611     ASSERT_TRUE(auto_size_msg);
612
613     int instance_id = 0;
614     bool needs_ack = false;
615     BrowserPluginHostMsg_AutoSize_Params auto_size_params;
616     BrowserPluginHostMsg_ResizeGuest_Params resize_params;
617     BrowserPluginHostMsg_UpdateRect_ACK::Read(auto_size_msg,
618                                               &instance_id,
619                                               &needs_ack,
620                                               &auto_size_params,
621                                               &resize_params);
622     EXPECT_FALSE(auto_size_params.enable);
623     // These value are not populated (as an optimization) if autosize is
624     // disabled.
625     EXPECT_EQ(0, auto_size_params.min_size.width());
626     EXPECT_EQ(0, auto_size_params.min_size.height());
627     EXPECT_EQ(0, auto_size_params.max_size.width());
628     EXPECT_EQ(0, auto_size_params.max_size.height());
629   }
630 }
631
632 }  // namespace content