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