Home | History | Annotate | Download | only in browser_plugin
      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;
    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;
    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;
    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   return static_cast<MockBrowserPlugin*>(
    176       browser_plugin_manager()->GetBrowserPlugin(instance_id));
    177 }
    178 
    179 // This test verifies that an initial resize occurs when we instantiate the
    180 // browser plugin. This test also verifies that the browser plugin is waiting
    181 // for a BrowserPluginMsg_UpdateRect in response. We issue an UpdateRect, and
    182 // we observe an UpdateRect_ACK, with the |pending_damage_buffer_| reset,
    183 // indiciating that the BrowserPlugin is not waiting for any more UpdateRects to
    184 // satisfy its resize request.
    185 TEST_F(BrowserPluginTest, InitialResize) {
    186   LoadHTML(GetHTMLForBrowserPluginObject().c_str());
    187   // Verify that the information in Attach is correct.
    188   BrowserPluginHostMsg_Attach_Params params;
    189   MockBrowserPlugin* browser_plugin = GetCurrentPluginWithAttachParams(&params);
    190 
    191   EXPECT_EQ(640, params.resize_guest_params.view_rect.width());
    192   EXPECT_EQ(480, params.resize_guest_params.view_rect.height());
    193   ASSERT_TRUE(browser_plugin);
    194   // Now the browser plugin is expecting a UpdateRect resize.
    195   int instance_id = browser_plugin->guest_instance_id();
    196   EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
    197 
    198   // Send the BrowserPlugin an UpdateRect equal to its container size with
    199   // the same damage buffer. That should clear |pending_damage_buffer_|.
    200   BrowserPluginMsg_UpdateRect_Params update_rect_params;
    201   update_rect_params.damage_buffer_sequence_id =
    202       browser_plugin->damage_buffer_sequence_id_;
    203   update_rect_params.view_size = gfx::Size(640, 480);
    204   update_rect_params.scale_factor = 1.0f;
    205   update_rect_params.is_resize_ack = true;
    206   update_rect_params.needs_ack = true;
    207   BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
    208   browser_plugin->OnMessageReceived(msg);
    209   EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
    210 }
    211 
    212 // This test verifies that all attributes (present at the time of writing) are
    213 // parsed on initialization. However, this test does minimal checking of
    214 // correct behavior.
    215 TEST_F(BrowserPluginTest, ParseAllAttributes) {
    216   std::string html = base::StringPrintf(kHTMLForBrowserPluginWithAllAttributes,
    217                                         content::kBrowserPluginMimeType);
    218   LoadHTML(html.c_str());
    219   bool result;
    220   bool has_value = ExecuteScriptAndReturnBool(
    221       "document.getElementById('browserplugin').autosize", &result);
    222   EXPECT_TRUE(has_value);
    223   EXPECT_TRUE(result);
    224   int maxHeight = ExecuteScriptAndReturnInt(
    225       "document.getElementById('browserplugin').maxheight");
    226   EXPECT_EQ(600, maxHeight);
    227   int maxWidth = ExecuteScriptAndReturnInt(
    228       "document.getElementById('browserplugin').maxwidth");
    229   EXPECT_EQ(800, maxWidth);
    230   int minHeight = ExecuteScriptAndReturnInt(
    231       "document.getElementById('browserplugin').minheight");
    232   EXPECT_EQ(240, minHeight);
    233   int minWidth = ExecuteScriptAndReturnInt(
    234       "document.getElementById('browserplugin').minwidth");
    235   EXPECT_EQ(320, minWidth);
    236   std::string name = ExecuteScriptAndReturnString(
    237       "document.getElementById('browserplugin').name");
    238   EXPECT_STREQ("Jim", name.c_str());
    239   std::string partition = ExecuteScriptAndReturnString(
    240       "document.getElementById('browserplugin').partition");
    241   EXPECT_STREQ("someid", partition.c_str());
    242   std::string src = ExecuteScriptAndReturnString(
    243       "document.getElementById('browserplugin').src");
    244   EXPECT_STREQ("foo", src.c_str());
    245 }
    246 
    247 // Verify that the src attribute on the browser plugin works as expected.
    248 TEST_F(BrowserPluginTest, SrcAttribute) {
    249   LoadHTML(GetHTMLForBrowserPluginObject().c_str());
    250   // Verify that we're reporting the correct URL to navigate to based on the
    251   // src attribute.
    252   {
    253     BrowserPluginHostMsg_Attach_Params params;
    254     MockBrowserPlugin* browser_plugin =
    255         GetCurrentPluginWithAttachParams(&params);
    256     ASSERT_TRUE(browser_plugin);
    257     EXPECT_EQ("foo", params.src);
    258   }
    259 
    260   browser_plugin_manager()->sink().ClearMessages();
    261   // Navigate to bar and observe the associated
    262   // BrowserPluginHostMsg_NavigateGuest message.
    263   // Verify that the src attribute is updated as well.
    264   ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
    265   {
    266     // Verify that we do not get a Attach on subsequent navigations.
    267     const IPC::Message* create_msg =
    268         browser_plugin_manager()->sink().GetUniqueMessageMatching(
    269             BrowserPluginHostMsg_Attach::ID);
    270     ASSERT_FALSE(create_msg);
    271 
    272     const IPC::Message* msg =
    273         browser_plugin_manager()->sink().GetUniqueMessageMatching(
    274             BrowserPluginHostMsg_NavigateGuest::ID);
    275     ASSERT_TRUE(msg);
    276 
    277     int instance_id = 0;
    278     std::string src;
    279     BrowserPluginHostMsg_NavigateGuest::Read(msg, &instance_id, &src);
    280     EXPECT_EQ("bar", src);
    281     std::string src_value =
    282         ExecuteScriptAndReturnString(
    283             "document.getElementById('browserplugin').src");
    284     EXPECT_EQ("bar", src_value);
    285   }
    286 }
    287 
    288 TEST_F(BrowserPluginTest, ResizeFlowControl) {
    289   LoadHTML(GetHTMLForBrowserPluginObject().c_str());
    290   MockBrowserPlugin* browser_plugin = GetCurrentPlugin();
    291   ASSERT_TRUE(browser_plugin);
    292   int instance_id = browser_plugin->guest_instance_id();
    293   EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
    294   // Send an UpdateRect to the BrowserPlugin to make it use the pending damage
    295   // buffer.
    296   {
    297     // We send a stale UpdateRect to the BrowserPlugin.
    298     BrowserPluginMsg_UpdateRect_Params update_rect_params;
    299     update_rect_params.view_size = gfx::Size(640, 480);
    300     update_rect_params.scale_factor = 1.0f;
    301     update_rect_params.is_resize_ack = true;
    302     update_rect_params.needs_ack = true;
    303     // By sending |damage_buffer_sequence_id| back to BrowserPlugin on
    304     // UpdateRect, then the BrowserPlugin knows that the browser process has
    305     // received and has begun to use the |pending_damage_buffer_|.
    306     update_rect_params.damage_buffer_sequence_id =
    307         browser_plugin->damage_buffer_sequence_id_;
    308     BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
    309     browser_plugin->OnMessageReceived(msg);
    310     EXPECT_EQ(NULL, browser_plugin->pending_damage_buffer_.get());
    311   }
    312 
    313   browser_plugin_manager()->sink().ClearMessages();
    314 
    315   // Resize the browser plugin three times.
    316   ExecuteJavaScript("document.getElementById('browserplugin').width = '641px'");
    317   ProcessPendingMessages();
    318   ExecuteJavaScript("document.getElementById('browserplugin').width = '642px'");
    319   ProcessPendingMessages();
    320   ExecuteJavaScript("document.getElementById('browserplugin').width = '643px'");
    321   ProcessPendingMessages();
    322 
    323   // Expect to see one resize messsage in the sink. BrowserPlugin will not issue
    324   // subsequent resize requests until the first request is satisfied by the
    325   // guest. The rest of the messages could be
    326   // BrowserPluginHostMsg_UpdateGeometry msgs.
    327   EXPECT_LE(1u, browser_plugin_manager()->sink().message_count());
    328   for (size_t i = 0; i < browser_plugin_manager()->sink().message_count();
    329        ++i) {
    330     const IPC::Message* msg = browser_plugin_manager()->sink().GetMessageAt(i);
    331     if (msg->type() != BrowserPluginHostMsg_ResizeGuest::ID)
    332       EXPECT_EQ(msg->type(), BrowserPluginHostMsg_UpdateGeometry::ID);
    333   }
    334   const IPC::Message* msg =
    335       browser_plugin_manager()->sink().GetUniqueMessageMatching(
    336           BrowserPluginHostMsg_ResizeGuest::ID);
    337   ASSERT_TRUE(msg);
    338   BrowserPluginHostMsg_ResizeGuest_Params params;
    339   BrowserPluginHostMsg_ResizeGuest::Read(msg, &instance_id, &params);
    340   EXPECT_EQ(641, params.view_rect.width());
    341   EXPECT_EQ(480, params.view_rect.height());
    342   // This indicates that the BrowserPlugin has sent out a previous resize
    343   // request but has not yet received an UpdateRect for that request.
    344   EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
    345 
    346   {
    347     // We send a stale UpdateRect to the BrowserPlugin.
    348     BrowserPluginMsg_UpdateRect_Params update_rect_params;
    349     update_rect_params.view_size = gfx::Size(641, 480);
    350     update_rect_params.scale_factor = 1.0f;
    351     update_rect_params.is_resize_ack = true;
    352     update_rect_params.needs_ack = true;
    353     update_rect_params.damage_buffer_sequence_id =
    354         browser_plugin->damage_buffer_sequence_id_;
    355     BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
    356     browser_plugin->OnMessageReceived(msg);
    357     // This tells us that the BrowserPlugin is still expecting another
    358     // UpdateRect with the most recent size.
    359     EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
    360   }
    361   // Send the BrowserPlugin another UpdateRect, but this time with a size
    362   // that matches the size of the container.
    363   {
    364     BrowserPluginMsg_UpdateRect_Params update_rect_params;
    365     update_rect_params.view_size = gfx::Size(643, 480);
    366     update_rect_params.scale_factor = 1.0f;
    367     update_rect_params.is_resize_ack = true;
    368     update_rect_params.needs_ack = true;
    369     update_rect_params.damage_buffer_sequence_id =
    370         browser_plugin->damage_buffer_sequence_id_;
    371     BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
    372     browser_plugin->OnMessageReceived(msg);
    373     // The BrowserPlugin has finally received an UpdateRect that satisifes
    374     // its current size, and so it is happy.
    375     EXPECT_FALSE(browser_plugin->pending_damage_buffer_.get());
    376   }
    377 }
    378 
    379 TEST_F(BrowserPluginTest, RemovePlugin) {
    380   LoadHTML(GetHTMLForBrowserPluginObject().c_str());
    381   EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
    382       BrowserPluginHostMsg_PluginDestroyed::ID));
    383   ExecuteJavaScript("x = document.getElementById('browserplugin'); "
    384                     "x.parentNode.removeChild(x);");
    385   ProcessPendingMessages();
    386   EXPECT_TRUE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
    387       BrowserPluginHostMsg_PluginDestroyed::ID));
    388 }
    389 
    390 // This test verifies that PluginDestroyed messages do not get sent from a
    391 // BrowserPlugin that has never navigated.
    392 TEST_F(BrowserPluginTest, RemovePluginBeforeNavigation) {
    393   std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
    394                                         content::kBrowserPluginMimeType);
    395   LoadHTML(html.c_str());
    396   EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
    397       BrowserPluginHostMsg_PluginDestroyed::ID));
    398   ExecuteJavaScript("x = document.getElementById('browserplugin'); "
    399                     "x.parentNode.removeChild(x);");
    400   ProcessPendingMessages();
    401   EXPECT_FALSE(browser_plugin_manager()->sink().GetUniqueMessageMatching(
    402       BrowserPluginHostMsg_PluginDestroyed::ID));
    403 }
    404 
    405 // Verify that the 'partition' attribute on the browser plugin is parsed
    406 // correctly.
    407 TEST_F(BrowserPluginTest, PartitionAttribute) {
    408   std::string html = base::StringPrintf(kHTMLForPartitionedPluginObject,
    409                                         content::kBrowserPluginMimeType);
    410   LoadHTML(html.c_str());
    411   std::string partition_value = ExecuteScriptAndReturnString(
    412       "document.getElementById('browserplugin').partition");
    413   EXPECT_STREQ("someid", partition_value.c_str());
    414 
    415   html = base::StringPrintf(kHTMLForPartitionedPersistedPluginObject,
    416                             content::kBrowserPluginMimeType);
    417   LoadHTML(html.c_str());
    418   partition_value = ExecuteScriptAndReturnString(
    419       "document.getElementById('browserplugin').partition");
    420   EXPECT_STREQ("persist:someid", partition_value.c_str());
    421 
    422   // Verify that once HTML has defined a source and partition, we cannot change
    423   // the partition anymore.
    424   ExecuteJavaScript(
    425       "try {"
    426       "  document.getElementById('browserplugin').partition = 'foo';"
    427       "  document.title = 'success';"
    428       "} catch (e) { document.title = e.message; }");
    429   std::string title = ExecuteScriptAndReturnString("document.title");
    430   EXPECT_STREQ(
    431       "The object has already navigated, so its partition cannot be changed.",
    432       title.c_str());
    433 
    434   // Load a browser tag without 'src' defined.
    435   html = base::StringPrintf(kHTMLForSourcelessPluginObject,
    436                             content::kBrowserPluginMimeType);
    437   LoadHTML(html.c_str());
    438 
    439   // Ensure we don't parse just "persist:" string and return exception.
    440   ExecuteJavaScript(
    441       "try {"
    442       "  document.getElementById('browserplugin').partition = 'persist:';"
    443       "  document.title = 'success';"
    444       "} catch (e) { document.title = e.message; }");
    445   title = ExecuteScriptAndReturnString("document.title");
    446   EXPECT_STREQ("Invalid partition attribute.", title.c_str());
    447 }
    448 
    449 // This test verifies that BrowserPlugin enters an error state when the
    450 // partition attribute is invalid.
    451 TEST_F(BrowserPluginTest, InvalidPartition) {
    452   std::string html = base::StringPrintf(kHTMLForInvalidPartitionedPluginObject,
    453                                         content::kBrowserPluginMimeType);
    454   LoadHTML(html.c_str());
    455   // Attempt to navigate with an invalid partition.
    456   {
    457     ExecuteJavaScript(
    458         "try {"
    459         "  document.getElementById('browserplugin').src = 'bar';"
    460         "  document.title = 'success';"
    461         "} catch (e) { document.title = e.message; }");
    462     std::string title = ExecuteScriptAndReturnString("document.title");
    463     EXPECT_STREQ("Invalid partition attribute.", title.c_str());
    464     // Verify that the 'src' attribute has not been updated.
    465     EXPECT_EQ("", ExecuteScriptAndReturnString(
    466         "document.getElementById('browserplugin').src"));
    467   }
    468 
    469   // Verify that the BrowserPlugin accepts changes to its src attribue after
    470   // setting the partition to a valid value.
    471   ExecuteJavaScript(
    472       "document.getElementById('browserplugin').partition = 'persist:foo'");
    473   ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
    474   EXPECT_EQ("bar", ExecuteScriptAndReturnString(
    475       "document.getElementById('browserplugin').src"));
    476   ProcessPendingMessages();
    477   // Verify that the BrowserPlugin does not 'deadlock': it can recover from
    478   // the partition ID error state.
    479   {
    480     ExecuteJavaScript(
    481         "try {"
    482         "  document.getElementById('browserplugin').partition = 'persist:1337';"
    483         "  document.title = 'success';"
    484         "} catch (e) { document.title = e.message; }");
    485     std::string title = ExecuteScriptAndReturnString("document.title");
    486     EXPECT_STREQ(
    487         "The object has already navigated, so its partition cannot be changed.",
    488         title.c_str());
    489     ExecuteJavaScript("document.getElementById('browserplugin').src = '42'");
    490     EXPECT_EQ("42", ExecuteScriptAndReturnString(
    491         "document.getElementById('browserplugin').src"));
    492   }
    493 }
    494 
    495 // Test to verify that after the first navigation, the partition attribute
    496 // cannot be modified.
    497 TEST_F(BrowserPluginTest, ImmutableAttributesAfterNavigation) {
    498   std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
    499                                         content::kBrowserPluginMimeType);
    500   LoadHTML(html.c_str());
    501 
    502   ExecuteJavaScript(
    503       "document.getElementById('browserplugin').partition = 'storage'");
    504   std::string partition_value = ExecuteScriptAndReturnString(
    505       "document.getElementById('browserplugin').partition");
    506   EXPECT_STREQ("storage", partition_value.c_str());
    507 
    508   std::string src_value = ExecuteScriptAndReturnString(
    509       "document.getElementById('browserplugin').src");
    510   EXPECT_STREQ("", src_value.c_str());
    511 
    512   ExecuteJavaScript("document.getElementById('browserplugin').src = 'bar'");
    513   ProcessPendingMessages();
    514   {
    515     BrowserPluginHostMsg_Attach_Params params;
    516     MockBrowserPlugin* browser_plugin =
    517         GetCurrentPluginWithAttachParams(&params);
    518     ASSERT_TRUE(browser_plugin);
    519 
    520     EXPECT_STREQ("storage", params.storage_partition_id.c_str());
    521     EXPECT_FALSE(params.persist_storage);
    522     EXPECT_STREQ("bar", params.src.c_str());
    523   }
    524 
    525   // Setting the partition should throw an exception and the value should not
    526   // change.
    527   ExecuteJavaScript(
    528       "try {"
    529       "  document.getElementById('browserplugin').partition = 'someid';"
    530       "  document.title = 'success';"
    531       "} catch (e) { document.title = e.message; }");
    532 
    533   std::string title = ExecuteScriptAndReturnString("document.title");
    534   EXPECT_STREQ(
    535       "The object has already navigated, so its partition cannot be changed.",
    536       title.c_str());
    537 
    538   partition_value = ExecuteScriptAndReturnString(
    539       "document.getElementById('browserplugin').partition");
    540   EXPECT_STREQ("storage", partition_value.c_str());
    541 }
    542 
    543 TEST_F(BrowserPluginTest, AutoSizeAttributes) {
    544   std::string html = base::StringPrintf(kHTMLForSourcelessPluginObject,
    545                                         content::kBrowserPluginMimeType);
    546   LoadHTML(html.c_str());
    547   const char* kSetAutoSizeParametersAndNavigate =
    548     "var browserplugin = document.getElementById('browserplugin');"
    549     "browserplugin.autosize = true;"
    550     "browserplugin.minwidth = 42;"
    551     "browserplugin.minheight = 43;"
    552     "browserplugin.maxwidth = 1337;"
    553     "browserplugin.maxheight = 1338;"
    554     "browserplugin.src = 'foobar';";
    555   const char* kDisableAutoSize =
    556     "document.getElementById('browserplugin').removeAttribute('autosize');";
    557 
    558   int instance_id = 0;
    559   // Set some autosize parameters before navigating then navigate.
    560   // Verify that the BrowserPluginHostMsg_Attach message contains
    561   // the correct autosize parameters.
    562   ExecuteJavaScript(kSetAutoSizeParametersAndNavigate);
    563   ProcessPendingMessages();
    564 
    565   BrowserPluginHostMsg_Attach_Params params;
    566   MockBrowserPlugin* browser_plugin =
    567       GetCurrentPluginWithAttachParams(&params);
    568   ASSERT_TRUE(browser_plugin);
    569 
    570   EXPECT_TRUE(params.auto_size_params.enable);
    571   EXPECT_EQ(42, params.auto_size_params.min_size.width());
    572   EXPECT_EQ(43, params.auto_size_params.min_size.height());
    573   EXPECT_EQ(1337, params.auto_size_params.max_size.width());
    574   EXPECT_EQ(1338, params.auto_size_params.max_size.height());
    575 
    576   // Verify that we are waiting for the browser process to grab the new
    577   // damage buffer.
    578   EXPECT_TRUE(browser_plugin->pending_damage_buffer_.get());
    579   // Disable autosize. AutoSize state will not be sent to the guest until
    580   // the guest has responded to the last resize request.
    581   ExecuteJavaScript(kDisableAutoSize);
    582   ProcessPendingMessages();
    583 
    584   const IPC::Message* auto_size_msg =
    585   browser_plugin_manager()->sink().GetUniqueMessageMatching(
    586       BrowserPluginHostMsg_SetAutoSize::ID);
    587   EXPECT_FALSE(auto_size_msg);
    588 
    589   // Send the BrowserPlugin an UpdateRect equal to its |max_size| with
    590   // the same damage buffer.
    591   BrowserPluginMsg_UpdateRect_Params update_rect_params;
    592   update_rect_params.damage_buffer_sequence_id =
    593       browser_plugin->damage_buffer_sequence_id_;
    594   update_rect_params.view_size = gfx::Size(1337, 1338);
    595   update_rect_params.scale_factor = 1.0f;
    596   update_rect_params.is_resize_ack = true;
    597   update_rect_params.needs_ack = true;
    598   BrowserPluginMsg_UpdateRect msg(instance_id, update_rect_params);
    599   browser_plugin->OnMessageReceived(msg);
    600 
    601   // Verify that the autosize state has been updated.
    602   {
    603     const IPC::Message* auto_size_msg =
    604     browser_plugin_manager()->sink().GetUniqueMessageMatching(
    605         BrowserPluginHostMsg_UpdateRect_ACK::ID);
    606     ASSERT_TRUE(auto_size_msg);
    607 
    608     int instance_id = 0;
    609     bool needs_ack = false;
    610     BrowserPluginHostMsg_AutoSize_Params auto_size_params;
    611     BrowserPluginHostMsg_ResizeGuest_Params resize_params;
    612     BrowserPluginHostMsg_UpdateRect_ACK::Read(auto_size_msg,
    613                                               &instance_id,
    614                                               &needs_ack,
    615                                               &auto_size_params,
    616                                               &resize_params);
    617     EXPECT_FALSE(auto_size_params.enable);
    618     // These value are not populated (as an optimization) if autosize is
    619     // disabled.
    620     EXPECT_EQ(0, auto_size_params.min_size.width());
    621     EXPECT_EQ(0, auto_size_params.min_size.height());
    622     EXPECT_EQ(0, auto_size_params.max_size.width());
    623     EXPECT_EQ(0, auto_size_params.max_size.height());
    624   }
    625 }
    626 
    627 }  // namespace content
    628