• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
number_of_pending_callbacks()23   size_t number_of_pending_callbacks() {
24     return callbacks_.size();
25   }
26 
canonical_list()27   std::vector<base::FilePath>* canonical_list() {
28     return &canonical_list_;
29   }
30 
next_load_index()31   size_t next_load_index() {
32     return next_load_index_;
33   }
34 
loaded_plugins()35   const std::vector<WebPluginInfo>& loaded_plugins() {
36     return loaded_plugins_;
37   }
38 
internal_plugins()39   std::vector<WebPluginInfo>* internal_plugins() {
40     return &internal_plugins_;
41   }
42 
RealLoadPluginsInternal()43   void RealLoadPluginsInternal() {
44     PluginLoaderPosix::LoadPluginsInternal();
45   }
46 
TestOnPluginLoaded(uint32 index,const WebPluginInfo & plugin)47   void TestOnPluginLoaded(uint32 index, const WebPluginInfo& plugin) {
48     OnPluginLoaded(index, plugin);
49   }
50 
TestOnPluginLoadFailed(uint32 index,const base::FilePath & path)51   void TestOnPluginLoadFailed(uint32 index, const base::FilePath& path) {
52     OnPluginLoadFailed(index, path);
53   }
54 
55  protected:
~MockPluginLoaderPosix()56   virtual ~MockPluginLoaderPosix() {}
57 };
58 
VerifyCallback(int * run_count,const std::vector<WebPluginInfo> &)59 void VerifyCallback(int* run_count, const std::vector<WebPluginInfo>&) {
60   ++(*run_count);
61 }
62 
63 class PluginLoaderPosixTest : public testing::Test {
64  public:
PluginLoaderPosixTest()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 
SetUp()77   virtual void SetUp() OVERRIDE {
78     PluginServiceImpl::GetInstance()->Init();
79   }
80 
message_loop()81   base::MessageLoop* message_loop() { return &message_loop_; }
plugin_loader()82   MockPluginLoaderPosix* plugin_loader() { return plugin_loader_.get(); }
83 
AddThreePlugins()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 
TEST_F(PluginLoaderPosixTest,QueueRequests)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 
TEST_F(PluginLoaderPosixTest,ThreeSuccessfulLoads)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 
TEST_F(PluginLoaderPosixTest,ThreeSuccessfulLoadsThenCrash)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 
TEST_F(PluginLoaderPosixTest,TwoFailures)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 
TEST_F(PluginLoaderPosixTest,CrashedProcess)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 
TEST_F(PluginLoaderPosixTest,InternalPlugin)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 
TEST_F(PluginLoaderPosixTest,AllCrashed)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