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