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