Home | History | Annotate | Download | only in browser
      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/browser/plugin_loader_posix.h"
      6 
      7 #include "base/at_exit.h"
      8 #include "base/bind.h"
      9 #include "base/files/file_path.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "content/browser/browser_thread_impl.h"
     14 #include "testing/gmock/include/gmock/gmock.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 namespace content {
     18 
     19 class MockPluginLoaderPosix : public PluginLoaderPosix {
     20  public:
     21   MOCK_METHOD0(LoadPluginsInternal, void(void));
     22 
     23   size_t number_of_pending_callbacks() {
     24     return callbacks_.size();
     25   }
     26 
     27   std::vector<base::FilePath>* canonical_list() {
     28     return &canonical_list_;
     29   }
     30 
     31   size_t next_load_index() {
     32     return next_load_index_;
     33   }
     34 
     35   const std::vector<WebPluginInfo>& loaded_plugins() {
     36     return loaded_plugins_;
     37   }
     38 
     39   std::vector<WebPluginInfo>* internal_plugins() {
     40     return &internal_plugins_;
     41   }
     42 
     43   void RealLoadPluginsInternal() {
     44     PluginLoaderPosix::LoadPluginsInternal();
     45   }
     46 
     47   void TestOnPluginLoaded(uint32 index, const WebPluginInfo& plugin) {
     48     OnPluginLoaded(index, plugin);
     49   }
     50 
     51   void TestOnPluginLoadFailed(uint32 index, const base::FilePath& path) {
     52     OnPluginLoadFailed(index, path);
     53   }
     54 
     55  protected:
     56   virtual ~MockPluginLoaderPosix() {}
     57 };
     58 
     59 void VerifyCallback(int* run_count, const std::vector<WebPluginInfo>&) {
     60   ++(*run_count);
     61 }
     62 
     63 class PluginLoaderPosixTest : public testing::Test {
     64  public:
     65   PluginLoaderPosixTest()
     66       : plugin1_(ASCIIToUTF16("plugin1"), base::FilePath("/tmp/one.plugin"),
     67                  ASCIIToUTF16("1.0"), base::string16()),
     68         plugin2_(ASCIIToUTF16("plugin2"), base::FilePath("/tmp/two.plugin"),
     69                  ASCIIToUTF16("2.0"), base::string16()),
     70         plugin3_(ASCIIToUTF16("plugin3"), base::FilePath("/tmp/three.plugin"),
     71                  ASCIIToUTF16("3.0"), base::string16()),
     72         file_thread_(BrowserThread::FILE, &message_loop_),
     73         io_thread_(BrowserThread::IO, &message_loop_),
     74         plugin_loader_(new MockPluginLoaderPosix) {
     75   }
     76 
     77   virtual void SetUp() OVERRIDE {
     78     PluginServiceImpl::GetInstance()->Init();
     79   }
     80 
     81   base::MessageLoop* message_loop() { return &message_loop_; }
     82   MockPluginLoaderPosix* plugin_loader() { return plugin_loader_.get(); }
     83 
     84   void AddThreePlugins() {
     85     plugin_loader_->canonical_list()->clear();
     86     plugin_loader_->canonical_list()->push_back(plugin1_.path);
     87     plugin_loader_->canonical_list()->push_back(plugin2_.path);
     88     plugin_loader_->canonical_list()->push_back(plugin3_.path);
     89   }
     90 
     91   // Data used for testing.
     92   WebPluginInfo plugin1_;
     93   WebPluginInfo plugin2_;
     94   WebPluginInfo plugin3_;
     95 
     96  private:
     97   base::ShadowingAtExitManager at_exit_manager_;  // Destroys PluginService.
     98 
     99   base::MessageLoopForIO message_loop_;
    100   BrowserThreadImpl file_thread_;
    101   BrowserThreadImpl io_thread_;
    102 
    103   scoped_refptr<MockPluginLoaderPosix> plugin_loader_;
    104 };
    105 
    106 TEST_F(PluginLoaderPosixTest, QueueRequests) {
    107   int did_callback = 0;
    108   PluginService::GetPluginsCallback callback =
    109       base::Bind(&VerifyCallback, base::Unretained(&did_callback));
    110 
    111   EXPECT_EQ(0u, plugin_loader()->number_of_pending_callbacks());
    112   plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback);
    113   EXPECT_EQ(1u, plugin_loader()->number_of_pending_callbacks());
    114 
    115   plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback);
    116   EXPECT_EQ(2u, plugin_loader()->number_of_pending_callbacks());
    117 
    118   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
    119   message_loop()->RunUntilIdle();
    120 
    121   EXPECT_EQ(0, did_callback);
    122 
    123   plugin_loader()->canonical_list()->clear();
    124   plugin_loader()->canonical_list()->push_back(plugin1_.path);
    125   plugin_loader()->TestOnPluginLoaded(0, plugin1_);
    126   message_loop()->RunUntilIdle();
    127 
    128   EXPECT_EQ(1, did_callback);
    129   EXPECT_EQ(1u, plugin_loader()->number_of_pending_callbacks());
    130 
    131   plugin_loader()->canonical_list()->clear();
    132   plugin_loader()->canonical_list()->push_back(plugin1_.path);
    133   plugin_loader()->TestOnPluginLoaded(0, plugin1_);
    134   message_loop()->RunUntilIdle();
    135 
    136   EXPECT_EQ(2, did_callback);
    137   EXPECT_EQ(0u, plugin_loader()->number_of_pending_callbacks());
    138 }
    139 
    140 TEST_F(PluginLoaderPosixTest, ThreeSuccessfulLoads) {
    141   int did_callback = 0;
    142   PluginService::GetPluginsCallback callback =
    143       base::Bind(&VerifyCallback, base::Unretained(&did_callback));
    144 
    145   plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback);
    146 
    147   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
    148   message_loop()->RunUntilIdle();
    149 
    150   AddThreePlugins();
    151 
    152   EXPECT_EQ(0u, plugin_loader()->next_load_index());
    153 
    154   const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
    155 
    156   plugin_loader()->TestOnPluginLoaded(0, plugin1_);
    157   EXPECT_EQ(1u, plugin_loader()->next_load_index());
    158   EXPECT_EQ(1u, plugins.size());
    159   EXPECT_EQ(plugin1_.name, plugins[0].name);
    160 
    161   message_loop()->RunUntilIdle();
    162   EXPECT_EQ(0, did_callback);
    163 
    164   plugin_loader()->TestOnPluginLoaded(1, plugin2_);
    165   EXPECT_EQ(2u, plugin_loader()->next_load_index());
    166   EXPECT_EQ(2u, plugins.size());
    167   EXPECT_EQ(plugin2_.name, plugins[1].name);
    168 
    169   message_loop()->RunUntilIdle();
    170   EXPECT_EQ(0, did_callback);
    171 
    172   plugin_loader()->TestOnPluginLoaded(2, plugin3_);
    173   EXPECT_EQ(3u, plugins.size());
    174   EXPECT_EQ(plugin3_.name, plugins[2].name);
    175 
    176   message_loop()->RunUntilIdle();
    177   EXPECT_EQ(1, did_callback);
    178 }
    179 
    180 TEST_F(PluginLoaderPosixTest, ThreeSuccessfulLoadsThenCrash) {
    181   int did_callback = 0;
    182   PluginService::GetPluginsCallback callback =
    183       base::Bind(&VerifyCallback, base::Unretained(&did_callback));
    184 
    185   plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback);
    186 
    187   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
    188   message_loop()->RunUntilIdle();
    189 
    190   AddThreePlugins();
    191 
    192   EXPECT_EQ(0u, plugin_loader()->next_load_index());
    193 
    194   const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
    195 
    196   plugin_loader()->TestOnPluginLoaded(0, plugin1_);
    197   EXPECT_EQ(1u, plugin_loader()->next_load_index());
    198   EXPECT_EQ(1u, plugins.size());
    199   EXPECT_EQ(plugin1_.name, plugins[0].name);
    200 
    201   message_loop()->RunUntilIdle();
    202   EXPECT_EQ(0, did_callback);
    203 
    204   plugin_loader()->TestOnPluginLoaded(1, plugin2_);
    205   EXPECT_EQ(2u, plugin_loader()->next_load_index());
    206   EXPECT_EQ(2u, plugins.size());
    207   EXPECT_EQ(plugin2_.name, plugins[1].name);
    208 
    209   message_loop()->RunUntilIdle();
    210   EXPECT_EQ(0, did_callback);
    211 
    212   plugin_loader()->TestOnPluginLoaded(2, plugin3_);
    213   EXPECT_EQ(3u, plugins.size());
    214   EXPECT_EQ(plugin3_.name, plugins[2].name);
    215 
    216   message_loop()->RunUntilIdle();
    217   EXPECT_EQ(1, did_callback);
    218 
    219   plugin_loader()->OnProcessCrashed(42);
    220 }
    221 
    222 TEST_F(PluginLoaderPosixTest, TwoFailures) {
    223   int did_callback = 0;
    224   PluginService::GetPluginsCallback callback =
    225       base::Bind(&VerifyCallback, base::Unretained(&did_callback));
    226 
    227   plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback);
    228 
    229   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
    230   message_loop()->RunUntilIdle();
    231 
    232   AddThreePlugins();
    233 
    234   EXPECT_EQ(0u, plugin_loader()->next_load_index());
    235 
    236   const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
    237 
    238   plugin_loader()->TestOnPluginLoadFailed(0, plugin1_.path);
    239   EXPECT_EQ(1u, plugin_loader()->next_load_index());
    240   EXPECT_EQ(0u, plugins.size());
    241 
    242   message_loop()->RunUntilIdle();
    243   EXPECT_EQ(0, did_callback);
    244 
    245   plugin_loader()->TestOnPluginLoaded(1, plugin2_);
    246   EXPECT_EQ(2u, plugin_loader()->next_load_index());
    247   EXPECT_EQ(1u, plugins.size());
    248   EXPECT_EQ(plugin2_.name, plugins[0].name);
    249 
    250   message_loop()->RunUntilIdle();
    251   EXPECT_EQ(0, did_callback);
    252 
    253   plugin_loader()->TestOnPluginLoadFailed(2, plugin3_.path);
    254   EXPECT_EQ(1u, plugins.size());
    255 
    256   message_loop()->RunUntilIdle();
    257   EXPECT_EQ(1, did_callback);
    258 }
    259 
    260 TEST_F(PluginLoaderPosixTest, CrashedProcess) {
    261   int did_callback = 0;
    262   PluginService::GetPluginsCallback callback =
    263       base::Bind(&VerifyCallback, base::Unretained(&did_callback));
    264 
    265   plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback);
    266 
    267   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
    268   message_loop()->RunUntilIdle();
    269 
    270   AddThreePlugins();
    271 
    272   EXPECT_EQ(0u, plugin_loader()->next_load_index());
    273 
    274   const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
    275 
    276   plugin_loader()->TestOnPluginLoaded(0, plugin1_);
    277   EXPECT_EQ(1u, plugin_loader()->next_load_index());
    278   EXPECT_EQ(1u, plugins.size());
    279   EXPECT_EQ(plugin1_.name, plugins[0].name);
    280 
    281   message_loop()->RunUntilIdle();
    282   EXPECT_EQ(0, did_callback);
    283 
    284   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
    285   plugin_loader()->OnProcessCrashed(42);
    286   EXPECT_EQ(1u, plugin_loader()->canonical_list()->size());
    287   EXPECT_EQ(0u, plugin_loader()->next_load_index());
    288   EXPECT_EQ(plugin3_.path.value(),
    289             plugin_loader()->canonical_list()->at(0).value());
    290 }
    291 
    292 TEST_F(PluginLoaderPosixTest, InternalPlugin) {
    293   int did_callback = 0;
    294   PluginService::GetPluginsCallback callback =
    295       base::Bind(&VerifyCallback, base::Unretained(&did_callback));
    296 
    297   plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback);
    298 
    299   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
    300   message_loop()->RunUntilIdle();
    301 
    302   plugin2_.path = base::FilePath("/internal/plugin.plugin");
    303 
    304   AddThreePlugins();
    305 
    306   plugin_loader()->internal_plugins()->clear();
    307   plugin_loader()->internal_plugins()->push_back(plugin2_);
    308 
    309   EXPECT_EQ(0u, plugin_loader()->next_load_index());
    310 
    311   const std::vector<WebPluginInfo>& plugins(plugin_loader()->loaded_plugins());
    312 
    313   plugin_loader()->TestOnPluginLoaded(0, plugin1_);
    314   EXPECT_EQ(1u, plugin_loader()->next_load_index());
    315   EXPECT_EQ(1u, plugins.size());
    316   EXPECT_EQ(plugin1_.name, plugins[0].name);
    317 
    318   message_loop()->RunUntilIdle();
    319   EXPECT_EQ(0, did_callback);
    320 
    321   // Internal plugins can fail to load if they're built-in with manual
    322   // entrypoint functions.
    323   plugin_loader()->TestOnPluginLoadFailed(1, plugin2_.path);
    324   EXPECT_EQ(2u, plugin_loader()->next_load_index());
    325   EXPECT_EQ(2u, plugins.size());
    326   EXPECT_EQ(plugin2_.name, plugins[1].name);
    327   EXPECT_EQ(0u, plugin_loader()->internal_plugins()->size());
    328 
    329   message_loop()->RunUntilIdle();
    330   EXPECT_EQ(0, did_callback);
    331 
    332   plugin_loader()->TestOnPluginLoaded(2, plugin3_);
    333   EXPECT_EQ(3u, plugins.size());
    334   EXPECT_EQ(plugin3_.name, plugins[2].name);
    335 
    336   message_loop()->RunUntilIdle();
    337   EXPECT_EQ(1, did_callback);
    338 }
    339 
    340 TEST_F(PluginLoaderPosixTest, AllCrashed) {
    341   int did_callback = 0;
    342   PluginService::GetPluginsCallback callback =
    343       base::Bind(&VerifyCallback, base::Unretained(&did_callback));
    344 
    345   plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback);
    346 
    347   // Spin the loop so that the canonical list of plugins can be set.
    348   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
    349   message_loop()->RunUntilIdle();
    350   AddThreePlugins();
    351 
    352   EXPECT_EQ(0u, plugin_loader()->next_load_index());
    353 
    354   // Mock the first two calls like normal.
    355   testing::Expectation first =
    356       EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
    357   // On the last call, go through the default impl.
    358   EXPECT_CALL(*plugin_loader(), LoadPluginsInternal())
    359       .After(first)
    360       .WillOnce(
    361           testing::Invoke(plugin_loader(),
    362                           &MockPluginLoaderPosix::RealLoadPluginsInternal));
    363   plugin_loader()->OnProcessCrashed(42);
    364   plugin_loader()->OnProcessCrashed(42);
    365   plugin_loader()->OnProcessCrashed(42);
    366 
    367   message_loop()->RunUntilIdle();
    368   EXPECT_EQ(1, did_callback);
    369 
    370   EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
    371 }
    372 
    373 }  // namespace content
    374