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
17namespace content {
18
19class MockPluginLoaderPosix : public PluginLoaderPosix {
20 public:
21  MOCK_METHOD0(LoadPluginsInternal, void(void));
22
23  size_t number_of_pending_callbacks() {
24    return callbacks_.size();
25  }
26
27  std::vector<base::FilePath>* canonical_list() {
28    return &canonical_list_;
29  }
30
31  size_t next_load_index() {
32    return next_load_index_;
33  }
34
35  const std::vector<WebPluginInfo>& loaded_plugins() {
36    return loaded_plugins_;
37  }
38
39  std::vector<WebPluginInfo>* internal_plugins() {
40    return &internal_plugins_;
41  }
42
43  void RealLoadPluginsInternal() {
44    PluginLoaderPosix::LoadPluginsInternal();
45  }
46
47  void TestOnPluginLoaded(uint32 index, const WebPluginInfo& plugin) {
48    OnPluginLoaded(index, plugin);
49  }
50
51  void TestOnPluginLoadFailed(uint32 index, const base::FilePath& path) {
52    OnPluginLoadFailed(index, path);
53  }
54
55 protected:
56  virtual ~MockPluginLoaderPosix() {}
57};
58
59void VerifyCallback(int* run_count, const std::vector<WebPluginInfo>&) {
60  ++(*run_count);
61}
62
63class PluginLoaderPosixTest : public testing::Test {
64 public:
65  PluginLoaderPosixTest()
66      : plugin1_(ASCIIToUTF16("plugin1"), base::FilePath("/tmp/one.plugin"),
67                 ASCIIToUTF16("1.0"), string16()),
68        plugin2_(ASCIIToUTF16("plugin2"), base::FilePath("/tmp/two.plugin"),
69                 ASCIIToUTF16("2.0"), string16()),
70        plugin3_(ASCIIToUTF16("plugin3"), base::FilePath("/tmp/three.plugin"),
71                 ASCIIToUTF16("3.0"), string16()),
72        file_thread_(BrowserThread::FILE, &message_loop_),
73        io_thread_(BrowserThread::IO, &message_loop_),
74        plugin_loader_(new MockPluginLoaderPosix) {
75  }
76
77  virtual void SetUp() OVERRIDE {
78    PluginServiceImpl::GetInstance()->Init();
79  }
80
81  base::MessageLoop* message_loop() { return &message_loop_; }
82  MockPluginLoaderPosix* plugin_loader() { return plugin_loader_.get(); }
83
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
106TEST_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
140TEST_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
180TEST_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
222TEST_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
260TEST_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
292TEST_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
340TEST_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