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 18using base::ASCIIToUTF16; 19 20namespace content { 21 22class MockPluginLoaderPosix : public PluginLoaderPosix { 23 public: 24 MOCK_METHOD0(LoadPluginsInternal, void(void)); 25 26 size_t number_of_pending_callbacks() { 27 return callbacks_.size(); 28 } 29 30 std::vector<base::FilePath>* canonical_list() { 31 return &canonical_list_; 32 } 33 34 size_t next_load_index() { 35 return next_load_index_; 36 } 37 38 const std::vector<WebPluginInfo>& loaded_plugins() { 39 return loaded_plugins_; 40 } 41 42 std::vector<WebPluginInfo>* internal_plugins() { 43 return &internal_plugins_; 44 } 45 46 void RealLoadPluginsInternal() { 47 PluginLoaderPosix::LoadPluginsInternal(); 48 } 49 50 void TestOnPluginLoaded(uint32 index, const WebPluginInfo& plugin) { 51 OnPluginLoaded(index, plugin); 52 } 53 54 void TestOnPluginLoadFailed(uint32 index, const base::FilePath& path) { 55 OnPluginLoadFailed(index, path); 56 } 57 58 protected: 59 virtual ~MockPluginLoaderPosix() {} 60}; 61 62void VerifyCallback(int* run_count, const std::vector<WebPluginInfo>&) { 63 ++(*run_count); 64} 65 66class PluginLoaderPosixTest : public testing::Test { 67 public: 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 80 virtual void SetUp() OVERRIDE { 81 PluginServiceImpl::GetInstance()->Init(); 82 } 83 84 base::MessageLoop* message_loop() { return &message_loop_; } 85 MockPluginLoaderPosix* plugin_loader() { return plugin_loader_.get(); } 86 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 110TEST_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 131TEST_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 166TEST_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 206TEST_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 248TEST_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 286TEST_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 318TEST_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 366TEST_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