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 "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 using base::ASCIIToUTF16
;
21 class MockPluginLoaderPosix
: public PluginLoaderPosix
{
23 MOCK_METHOD0(LoadPluginsInternal
, void(void));
25 size_t number_of_pending_callbacks() {
26 return callbacks_
.size();
29 std::vector
<base::FilePath
>* canonical_list() {
30 return &canonical_list_
;
33 size_t next_load_index() {
34 return next_load_index_
;
37 const std::vector
<WebPluginInfo
>& loaded_plugins() {
38 return loaded_plugins_
;
41 std::vector
<WebPluginInfo
>* internal_plugins() {
42 return &internal_plugins_
;
45 void RealLoadPluginsInternal() {
46 PluginLoaderPosix::LoadPluginsInternal();
49 void TestOnPluginLoaded(uint32 index
, const WebPluginInfo
& plugin
) {
50 OnPluginLoaded(index
, plugin
);
53 void TestOnPluginLoadFailed(uint32 index
, const base::FilePath
& path
) {
54 OnPluginLoadFailed(index
, path
);
58 virtual ~MockPluginLoaderPosix() {}
61 void VerifyCallback(int* run_count
, const std::vector
<WebPluginInfo
>&) {
65 class PluginLoaderPosixTest
: public testing::Test
{
67 PluginLoaderPosixTest()
68 : plugin1_(ASCIIToUTF16("plugin1"), base::FilePath("/tmp/one.plugin"),
69 ASCIIToUTF16("1.0"), base::string16()),
70 plugin2_(ASCIIToUTF16("plugin2"), base::FilePath("/tmp/two.plugin"),
71 ASCIIToUTF16("2.0"), base::string16()),
72 plugin3_(ASCIIToUTF16("plugin3"), base::FilePath("/tmp/three.plugin"),
73 ASCIIToUTF16("3.0"), base::string16()),
74 file_thread_(BrowserThread::FILE, &message_loop_
),
75 io_thread_(BrowserThread::IO
, &message_loop_
),
76 plugin_loader_(new MockPluginLoaderPosix
) {
79 virtual void SetUp() OVERRIDE
{
80 PluginServiceImpl::GetInstance()->Init();
83 base::MessageLoop
* message_loop() { return &message_loop_
; }
84 MockPluginLoaderPosix
* plugin_loader() { return plugin_loader_
.get(); }
86 void AddThreePlugins() {
87 plugin_loader_
->canonical_list()->clear();
88 plugin_loader_
->canonical_list()->push_back(plugin1_
.path
);
89 plugin_loader_
->canonical_list()->push_back(plugin2_
.path
);
90 plugin_loader_
->canonical_list()->push_back(plugin3_
.path
);
93 // Data used for testing.
94 WebPluginInfo plugin1_
;
95 WebPluginInfo plugin2_
;
96 WebPluginInfo plugin3_
;
99 base::ShadowingAtExitManager at_exit_manager_
; // Destroys PluginService.
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 EXPECT_EQ(0u, plugin_loader()->number_of_pending_callbacks());
114 plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback
);
115 EXPECT_EQ(1u, plugin_loader()->number_of_pending_callbacks());
117 plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback
);
118 EXPECT_EQ(2u, plugin_loader()->number_of_pending_callbacks());
120 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
121 message_loop()->RunUntilIdle();
123 EXPECT_EQ(0, did_callback
);
125 plugin_loader()->canonical_list()->clear();
126 plugin_loader()->canonical_list()->push_back(plugin1_
.path
);
127 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
128 message_loop()->RunUntilIdle();
130 EXPECT_EQ(1, did_callback
);
131 EXPECT_EQ(1u, plugin_loader()->number_of_pending_callbacks());
133 plugin_loader()->canonical_list()->clear();
134 plugin_loader()->canonical_list()->push_back(plugin1_
.path
);
135 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
136 message_loop()->RunUntilIdle();
138 EXPECT_EQ(2, did_callback
);
139 EXPECT_EQ(0u, plugin_loader()->number_of_pending_callbacks());
142 TEST_F(PluginLoaderPosixTest
, ThreeSuccessfulLoads
) {
143 int did_callback
= 0;
144 PluginService::GetPluginsCallback callback
=
145 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
147 plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback
);
149 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
150 message_loop()->RunUntilIdle();
154 EXPECT_EQ(0u, plugin_loader()->next_load_index());
156 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
158 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
159 EXPECT_EQ(1u, plugin_loader()->next_load_index());
160 EXPECT_EQ(1u, plugins
.size());
161 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
163 message_loop()->RunUntilIdle();
164 EXPECT_EQ(0, did_callback
);
166 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
167 EXPECT_EQ(2u, plugin_loader()->next_load_index());
168 EXPECT_EQ(2u, plugins
.size());
169 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
171 message_loop()->RunUntilIdle();
172 EXPECT_EQ(0, did_callback
);
174 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
175 EXPECT_EQ(3u, plugins
.size());
176 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
178 message_loop()->RunUntilIdle();
179 EXPECT_EQ(1, did_callback
);
182 TEST_F(PluginLoaderPosixTest
, ThreeSuccessfulLoadsThenCrash
) {
183 int did_callback
= 0;
184 PluginService::GetPluginsCallback callback
=
185 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
187 plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback
);
189 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
190 message_loop()->RunUntilIdle();
194 EXPECT_EQ(0u, plugin_loader()->next_load_index());
196 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
198 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
199 EXPECT_EQ(1u, plugin_loader()->next_load_index());
200 EXPECT_EQ(1u, plugins
.size());
201 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
203 message_loop()->RunUntilIdle();
204 EXPECT_EQ(0, did_callback
);
206 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
207 EXPECT_EQ(2u, plugin_loader()->next_load_index());
208 EXPECT_EQ(2u, plugins
.size());
209 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
211 message_loop()->RunUntilIdle();
212 EXPECT_EQ(0, did_callback
);
214 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
215 EXPECT_EQ(3u, plugins
.size());
216 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
218 message_loop()->RunUntilIdle();
219 EXPECT_EQ(1, did_callback
);
221 plugin_loader()->OnProcessCrashed(42);
224 TEST_F(PluginLoaderPosixTest
, TwoFailures
) {
225 int did_callback
= 0;
226 PluginService::GetPluginsCallback callback
=
227 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
229 plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback
);
231 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
232 message_loop()->RunUntilIdle();
236 EXPECT_EQ(0u, plugin_loader()->next_load_index());
238 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
240 plugin_loader()->TestOnPluginLoadFailed(0, plugin1_
.path
);
241 EXPECT_EQ(1u, plugin_loader()->next_load_index());
242 EXPECT_EQ(0u, plugins
.size());
244 message_loop()->RunUntilIdle();
245 EXPECT_EQ(0, did_callback
);
247 plugin_loader()->TestOnPluginLoaded(1, plugin2_
);
248 EXPECT_EQ(2u, plugin_loader()->next_load_index());
249 EXPECT_EQ(1u, plugins
.size());
250 EXPECT_EQ(plugin2_
.name
, plugins
[0].name
);
252 message_loop()->RunUntilIdle();
253 EXPECT_EQ(0, did_callback
);
255 plugin_loader()->TestOnPluginLoadFailed(2, plugin3_
.path
);
256 EXPECT_EQ(1u, plugins
.size());
258 message_loop()->RunUntilIdle();
259 EXPECT_EQ(1, did_callback
);
262 TEST_F(PluginLoaderPosixTest
, CrashedProcess
) {
263 int did_callback
= 0;
264 PluginService::GetPluginsCallback callback
=
265 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
267 plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback
);
269 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
270 message_loop()->RunUntilIdle();
274 EXPECT_EQ(0u, plugin_loader()->next_load_index());
276 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
278 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
279 EXPECT_EQ(1u, plugin_loader()->next_load_index());
280 EXPECT_EQ(1u, plugins
.size());
281 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
283 message_loop()->RunUntilIdle();
284 EXPECT_EQ(0, did_callback
);
286 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
287 plugin_loader()->OnProcessCrashed(42);
288 EXPECT_EQ(1u, plugin_loader()->canonical_list()->size());
289 EXPECT_EQ(0u, plugin_loader()->next_load_index());
290 EXPECT_EQ(plugin3_
.path
.value(),
291 plugin_loader()->canonical_list()->at(0).value());
294 TEST_F(PluginLoaderPosixTest
, InternalPlugin
) {
295 int did_callback
= 0;
296 PluginService::GetPluginsCallback callback
=
297 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
299 plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback
);
301 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
302 message_loop()->RunUntilIdle();
304 plugin2_
.path
= base::FilePath("/internal/plugin.plugin");
308 plugin_loader()->internal_plugins()->clear();
309 plugin_loader()->internal_plugins()->push_back(plugin2_
);
311 EXPECT_EQ(0u, plugin_loader()->next_load_index());
313 const std::vector
<WebPluginInfo
>& plugins(plugin_loader()->loaded_plugins());
315 plugin_loader()->TestOnPluginLoaded(0, plugin1_
);
316 EXPECT_EQ(1u, plugin_loader()->next_load_index());
317 EXPECT_EQ(1u, plugins
.size());
318 EXPECT_EQ(plugin1_
.name
, plugins
[0].name
);
320 message_loop()->RunUntilIdle();
321 EXPECT_EQ(0, did_callback
);
323 // Internal plugins can fail to load if they're built-in with manual
324 // entrypoint functions.
325 plugin_loader()->TestOnPluginLoadFailed(1, plugin2_
.path
);
326 EXPECT_EQ(2u, plugin_loader()->next_load_index());
327 EXPECT_EQ(2u, plugins
.size());
328 EXPECT_EQ(plugin2_
.name
, plugins
[1].name
);
329 EXPECT_EQ(0u, plugin_loader()->internal_plugins()->size());
331 message_loop()->RunUntilIdle();
332 EXPECT_EQ(0, did_callback
);
334 plugin_loader()->TestOnPluginLoaded(2, plugin3_
);
335 EXPECT_EQ(3u, plugins
.size());
336 EXPECT_EQ(plugin3_
.name
, plugins
[2].name
);
338 message_loop()->RunUntilIdle();
339 EXPECT_EQ(1, did_callback
);
342 TEST_F(PluginLoaderPosixTest
, AllCrashed
) {
343 int did_callback
= 0;
344 PluginService::GetPluginsCallback callback
=
345 base::Bind(&VerifyCallback
, base::Unretained(&did_callback
));
347 plugin_loader()->LoadPlugins(message_loop()->message_loop_proxy(), callback
);
349 // Spin the loop so that the canonical list of plugins can be set.
350 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(1);
351 message_loop()->RunUntilIdle();
354 EXPECT_EQ(0u, plugin_loader()->next_load_index());
356 // Mock the first two calls like normal.
357 testing::Expectation first
=
358 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal()).Times(2);
359 // On the last call, go through the default impl.
360 EXPECT_CALL(*plugin_loader(), LoadPluginsInternal())
363 testing::Invoke(plugin_loader(),
364 &MockPluginLoaderPosix::RealLoadPluginsInternal
));
365 plugin_loader()->OnProcessCrashed(42);
366 plugin_loader()->OnProcessCrashed(42);
367 plugin_loader()->OnProcessCrashed(42);
369 message_loop()->RunUntilIdle();
370 EXPECT_EQ(1, did_callback
);
372 EXPECT_EQ(0u, plugin_loader()->loaded_plugins().size());
375 } // namespace content