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 void TestOnPluginLoaded(uint32 index
, const WebPluginInfo
& plugin
) {
51 OnPluginLoaded(index
, plugin
);
54 void TestOnPluginLoadFailed(uint32 index
, const base::FilePath
& path
) {
55 OnPluginLoadFailed(index
, path
);
59 virtual ~MockPluginLoaderPosix() {}
62 void VerifyCallback(int* run_count
, const std::vector
<WebPluginInfo
>&) {
66 class PluginLoaderPosixTest
: public testing::Test
{
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
) {
80 void SetUp() override
{ PluginServiceImpl::GetInstance()->Init(); }
82 base::MessageLoop
* message_loop() { return &message_loop_
; }
83 MockPluginLoaderPosix
* plugin_loader() { return plugin_loader_
.get(); }
85 void AddThreePlugins() {
86 plugin_loader_
->canonical_list()->clear();
87 plugin_loader_
->canonical_list()->push_back(plugin1_
.path
);
88 plugin_loader_
->canonical_list()->push_back(plugin2_
.path
);
89 plugin_loader_
->canonical_list()->push_back(plugin3_
.path
);
92 // Data used for testing.
93 WebPluginInfo plugin1_
;
94 WebPluginInfo plugin2_
;
95 WebPluginInfo plugin3_
;
98 // Destroys PluginService and PluginList.
99 base::ShadowingAtExitManager at_exit_manager_
;
101 base::MessageLoopForIO message_loop_
;
102 BrowserThreadImpl file_thread_
;
103 BrowserThreadImpl io_thread_
;
105 scoped_refptr
<MockPluginLoaderPosix
> plugin_loader_
;
108 TEST_F(PluginLoaderPosixTest
, QueueRequests
) {
109 int did_callback
= 0;
110 PluginService::GetPluginsCallback callback
=
111 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
113 plugin_loader()->GetPlugins(callback
);
114 plugin_loader()->GetPlugins(callback
);
116 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
117 message_loop()->RunUntilIdle();
119 EXPECT_EQ(0, did_callback
);
121 plugin_loader()->canonical_list()->clear();
122 plugin_loader()->canonical_list()->push_back(plugin1_
.path
);
123 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
124 message_loop()->RunUntilIdle();
126 EXPECT_EQ(2, did_callback
);
129 TEST_F(PluginLoaderPosixTest
, QueueRequestsAndInvalidate
) {
130 int did_callback
= 0;
131 PluginService::GetPluginsCallback callback
=
132 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
134 plugin_loader()->GetPlugins(callback
);
136 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
137 message_loop()->RunUntilIdle();
139 EXPECT_EQ(0, did_callback
);
140 ::testing::Mock::VerifyAndClearExpectations(plugin_loader());
142 // Invalidate the plugin list, then queue up another request.
143 PluginList::Singleton()->RefreshPlugins();
144 plugin_loader()->GetPlugins(callback
);
146 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
148 plugin_loader()->canonical_list()->clear();
149 plugin_loader()->canonical_list()->push_back(plugin1_
.path
);
150 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
151 message_loop()->RunUntilIdle();
153 // Only the first request should have been fulfilled.
154 EXPECT_EQ(1, did_callback
);
156 plugin_loader()->canonical_list()->clear();
157 plugin_loader()->canonical_list()->push_back(plugin1_
.path
);
158 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
159 message_loop()->RunUntilIdle();
161 EXPECT_EQ(2, did_callback
);
164 TEST_F(PluginLoaderPosixTest
, ThreeSuccessfulLoads
) {
165 int did_callback
= 0;
166 PluginService::GetPluginsCallback callback
=
167 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
169 plugin_loader()->GetPlugins(callback
);
171 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
172 message_loop()->RunUntilIdle();
176 EXPECT_EQ(0u, plugin_loader()->next_load_index());
178 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
180 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
181 EXPECT_EQ(1u, plugin_loader()->next_load_index());
182 EXPECT_EQ(1u, plugins
.size());
183 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
185 message_loop()->RunUntilIdle();
186 EXPECT_EQ(0, did_callback
);
188 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
189 EXPECT_EQ(2u, plugin_loader()->next_load_index());
190 EXPECT_EQ(2u, plugins
.size());
191 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
193 message_loop()->RunUntilIdle();
194 EXPECT_EQ(0, did_callback
);
196 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
197 EXPECT_EQ(3u, plugins
.size());
198 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
200 message_loop()->RunUntilIdle();
201 EXPECT_EQ(1, did_callback
);
204 TEST_F(PluginLoaderPosixTest
, ThreeSuccessfulLoadsThenCrash
) {
205 int did_callback
= 0;
206 PluginService::GetPluginsCallback callback
=
207 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
209 plugin_loader()->GetPlugins(callback
);
211 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
212 message_loop()->RunUntilIdle();
216 EXPECT_EQ(0u, plugin_loader()->next_load_index());
218 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
220 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
221 EXPECT_EQ(1u, plugin_loader()->next_load_index());
222 EXPECT_EQ(1u, plugins
.size());
223 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
225 message_loop()->RunUntilIdle();
226 EXPECT_EQ(0, did_callback
);
228 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
229 EXPECT_EQ(2u, plugin_loader()->next_load_index());
230 EXPECT_EQ(2u, plugins
.size());
231 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
233 message_loop()->RunUntilIdle();
234 EXPECT_EQ(0, did_callback
);
236 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
237 EXPECT_EQ(3u, plugins
.size());
238 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
240 message_loop()->RunUntilIdle();
241 EXPECT_EQ(1, did_callback
);
243 plugin_loader()->OnProcessCrashed(42);
246 TEST_F(PluginLoaderPosixTest
, TwoFailures
) {
247 int did_callback
= 0;
248 PluginService::GetPluginsCallback callback
=
249 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
251 plugin_loader()->GetPlugins(callback
);
253 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
254 message_loop()->RunUntilIdle();
258 EXPECT_EQ(0u, plugin_loader()->next_load_index());
260 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
262 plugin_loader()->TestOnPluginLoadFailed(0, plugin1_
.path
);
263 EXPECT_EQ(1u, plugin_loader()->next_load_index());
264 EXPECT_EQ(0u, plugins
.size());
266 message_loop()->RunUntilIdle();
267 EXPECT_EQ(0, did_callback
);
269 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
270 EXPECT_EQ(2u, plugin_loader()->next_load_index());
271 EXPECT_EQ(1u, plugins
.size());
272 EXPECT_EQ(plugin2_
.name
, plugins
[0].name
);
274 message_loop()->RunUntilIdle();
275 EXPECT_EQ(0, did_callback
);
277 plugin_loader()->TestOnPluginLoadFailed(2, plugin3_
.path
);
278 EXPECT_EQ(1u, plugins
.size());
280 message_loop()->RunUntilIdle();
281 EXPECT_EQ(1, did_callback
);
284 TEST_F(PluginLoaderPosixTest
, CrashedProcess
) {
285 int did_callback
= 0;
286 PluginService::GetPluginsCallback callback
=
287 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
289 plugin_loader()->GetPlugins(callback
);
291 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
292 message_loop()->RunUntilIdle();
296 EXPECT_EQ(0u, plugin_loader()->next_load_index());
298 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
300 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
301 EXPECT_EQ(1u, plugin_loader()->next_load_index());
302 EXPECT_EQ(1u, plugins
.size());
303 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
305 message_loop()->RunUntilIdle();
306 EXPECT_EQ(0, did_callback
);
308 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
309 plugin_loader()->OnProcessCrashed(42);
310 EXPECT_EQ(1u, plugin_loader()->canonical_list()->size());
311 EXPECT_EQ(0u, plugin_loader()->next_load_index());
312 EXPECT_EQ(plugin3_
.path
.value(),
313 plugin_loader()->canonical_list()->at(0).value());
316 TEST_F(PluginLoaderPosixTest
, InternalPlugin
) {
317 int did_callback
= 0;
318 PluginService::GetPluginsCallback callback
=
319 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
321 plugin_loader()->GetPlugins(callback
);
323 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
324 message_loop()->RunUntilIdle();
326 plugin2_
.path
= base::FilePath("/internal/plugin.plugin");
330 plugin_loader()->internal_plugins()->clear();
331 plugin_loader()->internal_plugins()->push_back(plugin2_
);
333 EXPECT_EQ(0u, plugin_loader()->next_load_index());
335 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
337 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
338 EXPECT_EQ(1u, plugin_loader()->next_load_index());
339 EXPECT_EQ(1u, plugins
.size());
340 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
342 message_loop()->RunUntilIdle();
343 EXPECT_EQ(0, did_callback
);
345 // Internal plugins can fail to load if they're built-in with manual
346 // entrypoint functions.
347 plugin_loader()->TestOnPluginLoadFailed(1, plugin2_
.path
);
348 EXPECT_EQ(2u, plugin_loader()->next_load_index());
349 EXPECT_EQ(2u, plugins
.size());
350 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
351 EXPECT_EQ(0u, plugin_loader()->internal_plugins()->size());
353 message_loop()->RunUntilIdle();
354 EXPECT_EQ(0, did_callback
);
356 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
357 EXPECT_EQ(3u, plugins
.size());
358 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
360 message_loop()->RunUntilIdle();
361 EXPECT_EQ(1, did_callback
);
364 TEST_F(PluginLoaderPosixTest
, AllCrashed
) {
365 int did_callback
= 0;
366 PluginService::GetPluginsCallback callback
=
367 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
369 plugin_loader()->GetPlugins(callback
);
371 // Spin the loop so that the canonical list of plugins can be set.
372 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
373 message_loop()->RunUntilIdle();
376 EXPECT_EQ(0u, plugin_loader()->next_load_index());
378 // Mock the first two calls like normal.
379 testing::Expectation first
=
380 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
381 // On the last call, go through the default impl.
382 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal())
385 testing::Invoke(plugin_loader(),
386 &MockPluginLoaderPosix::RealLoadPluginsInternal
));
387 plugin_loader()->OnProcessCrashed(42);
388 plugin_loader()->OnProcessCrashed(42);
389 plugin_loader()->OnProcessCrashed(42);
391 message_loop()->RunUntilIdle();
392 EXPECT_EQ(1, did_callback
);
394 EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
397 } // namespace content