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