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.
8 #include "base/callback.h"
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/path_service.h"
13 #include "base/process_util.h"
14 #include "base/utf_string_conversions.h"
15 #include "chrome/browser/plugins/plugin_prefs.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/common/chrome_process_type.h"
19 #include "chrome/test/base/in_process_browser_test.h"
20 #include "chrome/test/base/ui_test_utils.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/browser_child_process_host_iterator.h"
23 #include "content/public/browser/child_process_data.h"
24 #include "content/public/browser/plugin_service.h"
25 #include "content/public/common/content_paths.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/test_utils.h"
28 #include "net/base/net_util.h"
29 #include "webkit/plugins/plugin_constants.h"
30 #include "webkit/plugins/webplugininfo.h"
32 using content::BrowserThread
;
36 class CallbackBarrier
: public base::RefCountedThreadSafe
<CallbackBarrier
> {
38 explicit CallbackBarrier(const base::Closure
& target_callback
)
39 : target_callback_(target_callback
),
40 outstanding_callbacks_(0),
44 base::Callback
<void(bool)> CreateCallback() {
45 outstanding_callbacks_
++;
46 return base::Bind(&CallbackBarrier::MayRunTargetCallback
, this);
50 friend class base::RefCountedThreadSafe
<CallbackBarrier
>;
53 EXPECT_TRUE(target_callback_
.is_null());
56 void MayRunTargetCallback(bool did_enable
) {
57 EXPECT_GT(outstanding_callbacks_
, 0);
58 did_enable_
= did_enable_
&& did_enable
;
59 if (--outstanding_callbacks_
== 0) {
60 EXPECT_TRUE(did_enable_
);
61 target_callback_
.Run();
62 target_callback_
.Reset();
66 base::Closure target_callback_
;
67 int outstanding_callbacks_
;
73 class ChromePluginTest
: public InProcessBrowserTest
{
77 static GURL
GetURL(const char* filename
) {
79 PathService::Get(content::DIR_TEST_DATA
, &path
);
80 path
= path
.AppendASCII("plugin").AppendASCII(filename
);
81 CHECK(file_util::PathExists(path
));
82 return net::FilePathToFileURL(path
);
85 static void LoadAndWait(Browser
* window
, const GURL
& url
, bool pass
) {
86 content::WebContents
* web_contents
=
87 window
->tab_strip_model()->GetActiveWebContents();
88 string16
expected_title(ASCIIToUTF16(pass
? "OK" : "plugin_not_found"));
89 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
90 title_watcher
.AlsoWaitForTitle(ASCIIToUTF16("FAIL"));
91 title_watcher
.AlsoWaitForTitle(ASCIIToUTF16(
92 pass
? "plugin_not_found" : "OK"));
93 ui_test_utils::NavigateToURL(window
, url
);
94 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
97 static void CrashFlash() {
98 scoped_refptr
<content::MessageLoopRunner
> runner
=
99 new content::MessageLoopRunner
;
100 BrowserThread::PostTask(
103 base::Bind(&CrashFlashInternal
, runner
->QuitClosure()));
107 static void GetFlashPath(std::vector
<base::FilePath
>* paths
) {
109 std::vector
<webkit::WebPluginInfo
> plugins
= GetPlugins();
110 for (std::vector
<webkit::WebPluginInfo
>::const_iterator it
=
111 plugins
.begin(); it
!= plugins
.end(); ++it
) {
112 if (it
->name
== ASCIIToUTF16(kFlashPluginName
))
113 paths
->push_back(it
->path
);
117 static std::vector
<webkit::WebPluginInfo
> GetPlugins() {
118 std::vector
<webkit::WebPluginInfo
> plugins
;
119 scoped_refptr
<content::MessageLoopRunner
> runner
=
120 new content::MessageLoopRunner
;
121 content::PluginService::GetInstance()->GetPlugins(
122 base::Bind(&GetPluginsInfoCallback
, &plugins
, runner
->QuitClosure()));
127 static void EnableFlash(bool enable
, Profile
* profile
) {
128 std::vector
<base::FilePath
> paths
;
129 GetFlashPath(&paths
);
130 ASSERT_FALSE(paths
.empty());
132 PluginPrefs
* plugin_prefs
= PluginPrefs::GetForProfile(profile
);
133 scoped_refptr
<content::MessageLoopRunner
> runner
=
134 new content::MessageLoopRunner
;
135 scoped_refptr
<CallbackBarrier
> callback_barrier(
136 new CallbackBarrier(runner
->QuitClosure()));
137 for (std::vector
<base::FilePath
>::iterator iter
= paths
.begin();
138 iter
!= paths
.end(); ++iter
) {
139 plugin_prefs
->EnablePlugin(enable
, *iter
,
140 callback_barrier
->CreateCallback());
145 static void EnsureFlashProcessCount(int expected
) {
147 scoped_refptr
<content::MessageLoopRunner
> runner
=
148 new content::MessageLoopRunner
;
149 BrowserThread::PostTask(
152 base::Bind(&CountPluginProcesses
, &actual
, runner
->QuitClosure()));
154 ASSERT_EQ(expected
, actual
);
158 static void CrashFlashInternal(const base::Closure
& quit_task
) {
160 for (content::BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
161 if (iter
.GetData().process_type
!= content::PROCESS_TYPE_PLUGIN
&&
162 iter
.GetData().process_type
!= content::PROCESS_TYPE_PPAPI_PLUGIN
) {
165 base::KillProcess(iter
.GetData().handle
, 0, true);
168 ASSERT_TRUE(found
) << "Didn't find Flash process!";
169 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_task
);
172 static void GetPluginsInfoCallback(
173 std::vector
<webkit::WebPluginInfo
>* rv
,
174 const base::Closure
& quit_task
,
175 const std::vector
<webkit::WebPluginInfo
>& plugins
) {
180 static void CountPluginProcesses(int* count
, const base::Closure
& quit_task
) {
181 for (content::BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
182 if (iter
.GetData().process_type
== content::PROCESS_TYPE_PLUGIN
||
183 iter
.GetData().process_type
== content::PROCESS_TYPE_PPAPI_PLUGIN
) {
187 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_task
);
191 // Tests a bunch of basic scenarios with Flash.
192 // This test fails under ASan on Mac, see http://crbug.com/147004.
193 // It fails elsewhere, too. See http://crbug.com/152071.
194 IN_PROC_BROWSER_TEST_F(ChromePluginTest
, DISABLED_Flash
) {
195 // Official builds always have bundled Flash.
196 #if !defined(OFFICIAL_BUILD)
197 std::vector
<base::FilePath
> flash_paths
;
198 GetFlashPath(&flash_paths
);
199 if (flash_paths
.empty()) {
200 LOG(INFO
) << "Test not running because couldn't find Flash.";
205 GURL url
= GetURL("flash.html");
206 EnsureFlashProcessCount(0);
209 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
210 EnsureFlashProcessCount(1);
211 Profile
* profile
= browser()->profile();
213 ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateBrowser(profile
), url
, true));
214 // Try an incognito window.
215 ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateIncognitoBrowser(), url
, true));
216 EnsureFlashProcessCount(1);
218 // Now kill Flash process and verify it reloads.
220 EnsureFlashProcessCount(0);
222 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
223 EnsureFlashProcessCount(1);
225 // Now try disabling it.
226 EnableFlash(false, profile
);
229 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, false));
230 EnsureFlashProcessCount(0);
232 // Now enable it again.
233 EnableFlash(true, profile
);
234 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
235 EnsureFlashProcessCount(1);
238 // Verify that the official builds have the known set of plugins.
239 IN_PROC_BROWSER_TEST_F(ChromePluginTest
, InstalledPlugins
) {
240 #if !defined(OFFICIAL_BUILD)
243 const char* expected
[] = {
247 "Chrome Remote Desktop Viewer",
248 #if defined(OS_CHROMEOS)
249 "Google Talk Plugin",
250 "Google Talk Plugin Video Accelerator",
255 std::vector
<webkit::WebPluginInfo
> plugins
= GetPlugins();
256 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(expected
); ++i
) {
258 for (; j
< plugins
.size(); ++j
) {
259 if (plugins
[j
].name
== ASCIIToUTF16(expected
[i
]))
262 ASSERT_TRUE(j
!= plugins
.size()) << "Didn't find " << expected
[i
];