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.
5 #include "content/browser/plugin_loader_posix.h"
7 #include "base/at_exit.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"
18 using base::ASCIIToUTF16
;
22 class MockPluginLoaderPosix
: public PluginLoaderPosix
{
24 MOCK_METHOD0(LoadPluginsInternal
, void(void));
26 size_t number_of_pending_callbacks() {
27 return callbacks_
.size();
30 std::vector
<base::FilePath
>* canonical_list() {
31 return &canonical_list_
;
34 size_t next_load_index() {
35 return next_load_index_
;
38 const std::vector
<WebPluginInfo
>& loaded_plugins() {
39 return loaded_plugins_
;
42 std::vector
<WebPluginInfo
>* internal_plugins() {
43 return &internal_plugins_
;
46 void RealLoadPluginsInternal() {
47 PluginLoaderPosix::LoadPluginsInternal();
50 bool LaunchUtilityProcess() override
{
51 // This method always does nothing and returns false. The actual
52 // implementation of this method launches another process, which is not
53 // very unit_test friendly.
57 void TestOnPluginLoaded(uint32 index
, const WebPluginInfo
& plugin
) {
58 OnPluginLoaded(index
, plugin
);
61 void TestOnPluginLoadFailed(uint32 index
, const base::FilePath
& path
) {
62 OnPluginLoadFailed(index
, path
);
66 virtual ~MockPluginLoaderPosix() {}
69 void VerifyCallback(int* run_count
, const std::vector
<WebPluginInfo
>&) {
73 class PluginLoaderPosixTest
: public testing::Test
{
75 PluginLoaderPosixTest()
76 : plugin1_(ASCIIToUTF16("plugin1"), base::FilePath("/tmp/one.plugin"),
77 ASCIIToUTF16("1.0"), base::string16()),
78 plugin2_(ASCIIToUTF16("plugin2"), base::FilePath("/tmp/two.plugin"),
79 ASCIIToUTF16("2.0"), base::string16()),
80 plugin3_(ASCIIToUTF16("plugin3"), base::FilePath("/tmp/three.plugin"),
81 ASCIIToUTF16("3.0"), base::string16()),
82 file_thread_(BrowserThread::FILE, &message_loop_
),
83 io_thread_(BrowserThread::IO
, &message_loop_
),
84 plugin_loader_(new MockPluginLoaderPosix
) {
87 void SetUp() override
{ PluginServiceImpl::GetInstance()->Init(); }
89 base::MessageLoop
* message_loop() { return &message_loop_
; }
90 MockPluginLoaderPosix
* plugin_loader() { return plugin_loader_
.get(); }
92 void AddThreePlugins() {
93 plugin_loader_
->canonical_list()->clear();
94 plugin_loader_
->canonical_list()->push_back(plugin1_
.path
);
95 plugin_loader_
->canonical_list()->push_back(plugin2_
.path
);
96 plugin_loader_
->canonical_list()->push_back(plugin3_
.path
);
99 // Data used for testing.
100 WebPluginInfo plugin1_
;
101 WebPluginInfo plugin2_
;
102 WebPluginInfo plugin3_
;
105 // Destroys PluginService and PluginList.
106 base::ShadowingAtExitManager at_exit_manager_
;
108 base::MessageLoopForIO message_loop_
;
109 BrowserThreadImpl file_thread_
;
110 BrowserThreadImpl io_thread_
;
112 scoped_refptr
<MockPluginLoaderPosix
> plugin_loader_
;
115 TEST_F(PluginLoaderPosixTest
, QueueRequests
) {
116 int did_callback
= 0;
117 PluginService::GetPluginsCallback callback
=
118 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
120 plugin_loader()->GetPlugins(callback
);
121 plugin_loader()->GetPlugins(callback
);
123 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
124 message_loop()->RunUntilIdle();
126 EXPECT_EQ(0, did_callback
);
128 plugin_loader()->canonical_list()->clear();
129 plugin_loader()->canonical_list()->push_back(plugin1_
.path
);
130 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
131 message_loop()->RunUntilIdle();
133 EXPECT_EQ(2, did_callback
);
136 TEST_F(PluginLoaderPosixTest
, QueueRequestsAndInvalidate
) {
137 int did_callback
= 0;
138 PluginService::GetPluginsCallback callback
=
139 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
141 plugin_loader()->GetPlugins(callback
);
143 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
144 message_loop()->RunUntilIdle();
146 EXPECT_EQ(0, did_callback
);
147 ::testing::Mock::VerifyAndClearExpectations(plugin_loader());
149 // Invalidate the plugin list, then queue up another request.
150 PluginList::Singleton()->RefreshPlugins();
151 plugin_loader()->GetPlugins(callback
);
153 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
155 plugin_loader()->canonical_list()->clear();
156 plugin_loader()->canonical_list()->push_back(plugin1_
.path
);
157 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
158 message_loop()->RunUntilIdle();
160 // Only the first request should have been fulfilled.
161 EXPECT_EQ(1, did_callback
);
163 plugin_loader()->canonical_list()->clear();
164 plugin_loader()->canonical_list()->push_back(plugin1_
.path
);
165 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
166 message_loop()->RunUntilIdle();
168 EXPECT_EQ(2, did_callback
);
171 TEST_F(PluginLoaderPosixTest
, ThreeSuccessfulLoads
) {
172 int did_callback
= 0;
173 PluginService::GetPluginsCallback callback
=
174 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
176 plugin_loader()->GetPlugins(callback
);
178 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
179 message_loop()->RunUntilIdle();
183 EXPECT_EQ(0u, plugin_loader()->next_load_index());
185 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
187 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
188 EXPECT_EQ(1u, plugin_loader()->next_load_index());
189 EXPECT_EQ(1u, plugins
.size());
190 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
192 message_loop()->RunUntilIdle();
193 EXPECT_EQ(0, did_callback
);
195 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
196 EXPECT_EQ(2u, plugin_loader()->next_load_index());
197 EXPECT_EQ(2u, plugins
.size());
198 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
200 message_loop()->RunUntilIdle();
201 EXPECT_EQ(0, did_callback
);
203 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
204 EXPECT_EQ(3u, plugins
.size());
205 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
207 message_loop()->RunUntilIdle();
208 EXPECT_EQ(1, did_callback
);
211 TEST_F(PluginLoaderPosixTest
, ThreeSuccessfulLoadsThenCrash
) {
212 int did_callback
= 0;
213 PluginService::GetPluginsCallback callback
=
214 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
216 plugin_loader()->GetPlugins(callback
);
218 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
219 message_loop()->RunUntilIdle();
223 EXPECT_EQ(0u, plugin_loader()->next_load_index());
225 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
227 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
228 EXPECT_EQ(1u, plugin_loader()->next_load_index());
229 EXPECT_EQ(1u, plugins
.size());
230 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
232 message_loop()->RunUntilIdle();
233 EXPECT_EQ(0, did_callback
);
235 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
236 EXPECT_EQ(2u, plugin_loader()->next_load_index());
237 EXPECT_EQ(2u, plugins
.size());
238 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
240 message_loop()->RunUntilIdle();
241 EXPECT_EQ(0, did_callback
);
243 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
244 EXPECT_EQ(3u, plugins
.size());
245 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
247 message_loop()->RunUntilIdle();
248 EXPECT_EQ(1, did_callback
);
250 plugin_loader()->OnProcessCrashed(42);
253 TEST_F(PluginLoaderPosixTest
, TwoFailures
) {
254 int did_callback
= 0;
255 PluginService::GetPluginsCallback callback
=
256 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
258 plugin_loader()->GetPlugins(callback
);
260 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
261 message_loop()->RunUntilIdle();
265 EXPECT_EQ(0u, plugin_loader()->next_load_index());
267 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
269 plugin_loader()->TestOnPluginLoadFailed(0, plugin1_
.path
);
270 EXPECT_EQ(1u, plugin_loader()->next_load_index());
271 EXPECT_EQ(0u, plugins
.size());
273 message_loop()->RunUntilIdle();
274 EXPECT_EQ(0, did_callback
);
276 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
277 EXPECT_EQ(2u, plugin_loader()->next_load_index());
278 EXPECT_EQ(1u, plugins
.size());
279 EXPECT_EQ(plugin2_
.name
, plugins
[0].name
);
281 message_loop()->RunUntilIdle();
282 EXPECT_EQ(0, did_callback
);
284 plugin_loader()->TestOnPluginLoadFailed(2, plugin3_
.path
);
285 EXPECT_EQ(1u, plugins
.size());
287 message_loop()->RunUntilIdle();
288 EXPECT_EQ(1, did_callback
);
291 TEST_F(PluginLoaderPosixTest
, CrashedProcess
) {
292 int did_callback
= 0;
293 PluginService::GetPluginsCallback callback
=
294 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
296 plugin_loader()->GetPlugins(callback
);
298 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
299 message_loop()->RunUntilIdle();
303 EXPECT_EQ(0u, plugin_loader()->next_load_index());
305 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
307 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
308 EXPECT_EQ(1u, plugin_loader()->next_load_index());
309 EXPECT_EQ(1u, plugins
.size());
310 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
312 message_loop()->RunUntilIdle();
313 EXPECT_EQ(0, did_callback
);
315 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
316 plugin_loader()->OnProcessCrashed(42);
317 EXPECT_EQ(1u, plugin_loader()->canonical_list()->size());
318 EXPECT_EQ(0u, plugin_loader()->next_load_index());
319 EXPECT_EQ(plugin3_
.path
.value(),
320 plugin_loader()->canonical_list()->at(0).value());
323 TEST_F(PluginLoaderPosixTest
, InternalPlugin
) {
324 int did_callback
= 0;
325 PluginService::GetPluginsCallback callback
=
326 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
328 plugin_loader()->GetPlugins(callback
);
330 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
331 message_loop()->RunUntilIdle();
333 plugin2_
.path
= base::FilePath("/internal/plugin.plugin");
337 plugin_loader()->internal_plugins()->clear();
338 plugin_loader()->internal_plugins()->push_back(plugin2_
);
340 EXPECT_EQ(0u, plugin_loader()->next_load_index());
342 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
344 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
345 EXPECT_EQ(1u, plugin_loader()->next_load_index());
346 EXPECT_EQ(1u, plugins
.size());
347 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
349 message_loop()->RunUntilIdle();
350 EXPECT_EQ(0, did_callback
);
352 // Internal plugins can fail to load if they're built-in with manual
353 // entrypoint functions.
354 plugin_loader()->TestOnPluginLoadFailed(1, plugin2_
.path
);
355 EXPECT_EQ(2u, plugin_loader()->next_load_index());
356 EXPECT_EQ(2u, plugins
.size());
357 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
358 EXPECT_EQ(0u, plugin_loader()->internal_plugins()->size());
360 message_loop()->RunUntilIdle();
361 EXPECT_EQ(0, did_callback
);
363 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
364 EXPECT_EQ(3u, plugins
.size());
365 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
367 message_loop()->RunUntilIdle();
368 EXPECT_EQ(1, did_callback
);
371 TEST_F(PluginLoaderPosixTest
, AllCrashed
) {
372 int did_callback
= 0;
373 PluginService::GetPluginsCallback callback
=
374 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
376 plugin_loader()->GetPlugins(callback
);
378 // Spin the loop so that the canonical list of plugins can be set.
379 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
380 message_loop()->RunUntilIdle();
383 EXPECT_EQ(0u, plugin_loader()->next_load_index());
385 // Mock the first two calls like normal.
386 testing::Expectation first
=
387 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
388 // On the last call, go through the default impl.
389 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal())
392 testing::Invoke(plugin_loader(),
393 &MockPluginLoaderPosix::RealLoadPluginsInternal
));
394 plugin_loader()->OnProcessCrashed(42);
395 plugin_loader()->OnProcessCrashed(42);
396 plugin_loader()->OnProcessCrashed(42);
398 message_loop()->RunUntilIdle();
399 EXPECT_EQ(1, did_callback
);
401 EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
404 TEST_F(PluginLoaderPosixTest
, PluginLaunchFailed
) {
405 int did_callback
= 0;
406 PluginService::GetPluginsCallback callback
=
407 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
409 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal())
410 .WillOnce(testing::Invoke(
411 plugin_loader(), &MockPluginLoaderPosix::RealLoadPluginsInternal
));
413 plugin_loader()->GetPlugins(callback
);
414 message_loop()->RunUntilIdle();
415 EXPECT_EQ(1, did_callback
);
416 EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
418 // TODO(erikchen): This is a genuine leak that should be fixed.
419 // https://code.google.com/p/chromium/issues/detail?id=431906
420 testing::Mock::AllowLeak(plugin_loader());
423 } // namespace content