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