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 17 namespace content { 18 19 class 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 59 void VerifyCallback(int* run_count, const std::vector<WebPluginInfo>&) { 60 ++(*run_count); 61 } 62 63 class PluginLoaderPosixTest : public testing::Test { 64 public: 65 PluginLoaderPosixTest() 66 : plugin1_(ASCIIToUTF16("plugin1"), base::FilePath("/tmp/one.plugin"), 67 ASCIIToUTF16("1.0"), base::string16()), 68 plugin2_(ASCIIToUTF16("plugin2"), base::FilePath("/tmp/two.plugin"), 69 ASCIIToUTF16("2.0"), base::string16()), 70 plugin3_(ASCIIToUTF16("plugin3"), base::FilePath("/tmp/three.plugin"), 71 ASCIIToUTF16("3.0"), base::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 106 TEST_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 140 TEST_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 180 TEST_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 222 TEST_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 260 TEST_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 292 TEST_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 340 TEST_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