[content shell] implement testRunner.overridePreference
[chromium-blink-merge.git] / content / browser / plugin_service_impl_browsertest.cc
blob78ede71b868ff4bfddcc34b1c884b6a46f894944
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_service_impl.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/path_service.h"
11 #include "content/public/browser/browser_context.h"
12 #include "content/public/browser/resource_context.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/common/content_switches.h"
15 #include "content/public/test/test_browser_thread.h"
16 #include "content/public/test/test_utils.h"
17 #include "content/shell/shell.h"
18 #include "content/test/content_browser_test.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "webkit/plugins/npapi/plugin_list.h"
22 namespace content {
24 const char kNPAPITestPluginMimeType[] = "application/vnd.npapi-test";
26 void OpenChannel(PluginProcessHost::Client* client) {
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
28 // Start opening the channel
29 PluginServiceImpl::GetInstance()->OpenChannelToNpapiPlugin(
30 0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client);
33 // Mock up of the Client and the Listener classes that would supply the
34 // communication channel with the plugin.
35 class MockPluginProcessHostClient : public PluginProcessHost::Client,
36 public IPC::Listener {
37 public:
38 MockPluginProcessHostClient(ResourceContext* context)
39 : context_(context),
40 channel_(NULL),
41 set_plugin_info_called_(false) {
44 virtual ~MockPluginProcessHostClient() {
45 if (channel_)
46 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_);
49 // PluginProcessHost::Client implementation.
50 virtual int ID() OVERRIDE { return 42; }
51 virtual bool OffTheRecord() OVERRIDE { return false; }
52 virtual ResourceContext* GetResourceContext() OVERRIDE {
53 return context_;
55 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {}
56 virtual void OnSentPluginChannelRequest() OVERRIDE {}
58 virtual void OnChannelOpened(const IPC::ChannelHandle& handle) OVERRIDE {
59 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
60 ASSERT_TRUE(set_plugin_info_called_);
61 ASSERT_TRUE(!channel_);
62 channel_ = new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this);
63 ASSERT_TRUE(channel_->Connect());
66 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
67 ASSERT_TRUE(info.mime_types.size());
68 ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
69 set_plugin_info_called_ = true;
72 virtual void OnError() OVERRIDE {
73 Fail();
76 // IPC::Listener implementation.
77 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
78 Fail();
79 return false;
81 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
82 QuitMessageLoop();
84 virtual void OnChannelError() OVERRIDE {
85 Fail();
87 #if defined(OS_POSIX)
88 virtual void OnChannelDenied() OVERRIDE {
89 Fail();
91 virtual void OnChannelListenError() OVERRIDE {
92 Fail();
94 #endif
96 private:
97 void Fail() {
98 FAIL();
99 QuitMessageLoop();
102 void QuitMessageLoop() {
103 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
104 MessageLoop::QuitClosure());
107 ResourceContext* context_;
108 IPC::Channel* channel_;
109 bool set_plugin_info_called_;
110 DISALLOW_COPY_AND_ASSIGN(MockPluginProcessHostClient);
113 class PluginServiceTest : public ContentBrowserTest {
114 public:
115 PluginServiceTest() {}
117 ResourceContext* GetResourceContext() {
118 return shell()->web_contents()->GetBrowserContext()->GetResourceContext();
121 virtual void SetUpCommandLine(CommandLine* command_line) {
122 #ifdef OS_MACOSX
123 FilePath browser_directory;
124 PathService::Get(base::DIR_MODULE, &browser_directory);
125 command_line->AppendSwitchPath(switches::kExtraPluginDir,
126 browser_directory.AppendASCII("plugins"));
127 #endif
128 // TODO(jam): since these plugin tests are running under Chrome, we need to
129 // tell it to disable its security features for old plugins. Once this is
130 // running under content_browsertests, these flags won't be needed.
131 // http://crbug.com/90448
132 // switches::kAlwaysAuthorizePlugins
133 command_line->AppendSwitch("always-authorize-plugins");
137 // Try to open a channel to the test plugin. Minimal plugin process spawning
138 // test for the PluginService interface.
139 IN_PROC_BROWSER_TEST_F(PluginServiceTest, OpenChannelToPlugin) {
140 MockPluginProcessHostClient mock_client(GetResourceContext());
141 BrowserThread::PostTask(
142 BrowserThread::IO, FROM_HERE,
143 base::Bind(&OpenChannel, &mock_client));
144 RunMessageLoop();
147 // A strict mock that fails if any of the methods are called. They shouldn't be
148 // called since the request should get canceled before then.
149 class MockCanceledPluginServiceClient : public PluginProcessHost::Client {
150 public:
151 MockCanceledPluginServiceClient(ResourceContext* context)
152 : context_(context),
153 get_resource_context_called_(false) {
156 virtual ~MockCanceledPluginServiceClient() {}
158 // Client implementation.
159 MOCK_METHOD0(ID, int());
160 virtual ResourceContext* GetResourceContext() OVERRIDE {
161 get_resource_context_called_ = true;
162 return context_;
164 MOCK_METHOD0(OffTheRecord, bool());
165 MOCK_METHOD1(OnFoundPluginProcessHost, void(PluginProcessHost* host));
166 MOCK_METHOD0(OnSentPluginChannelRequest, void());
167 MOCK_METHOD1(OnChannelOpened, void(const IPC::ChannelHandle& handle));
168 MOCK_METHOD1(SetPluginInfo, void(const webkit::WebPluginInfo& info));
169 MOCK_METHOD0(OnError, void());
171 bool get_resource_context_called() const {
172 return get_resource_context_called_;
175 private:
176 ResourceContext* context_;
177 bool get_resource_context_called_;
179 DISALLOW_COPY_AND_ASSIGN(MockCanceledPluginServiceClient);
182 void QuitUIMessageLoopFromIOThread() {
183 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
184 MessageLoop::QuitClosure());
187 void OpenChannelAndThenCancel(PluginProcessHost::Client* client) {
188 OpenChannel(client);
189 // Immediately cancel it. This is guaranteed to work since PluginService needs
190 // to consult its filter on the FILE thread.
191 PluginServiceImpl::GetInstance()->CancelOpenChannelToNpapiPlugin(client);
192 // Before we terminate the test, add a roundtrip through the FILE thread to
193 // make sure that it's had a chance to post back to the IO thread. Then signal
194 // the UI thread to stop and exit the test.
195 BrowserThread::PostTaskAndReply(
196 BrowserThread::FILE, FROM_HERE,
197 base::Bind(&base::DoNothing),
198 base::Bind(&QuitUIMessageLoopFromIOThread));
201 // Should not attempt to open a channel, since it should be canceled early on.
202 IN_PROC_BROWSER_TEST_F(PluginServiceTest, CancelOpenChannelToPluginService) {
203 ::testing::StrictMock<MockCanceledPluginServiceClient> mock_client(
204 GetResourceContext());
205 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
206 base::Bind(OpenChannelAndThenCancel, &mock_client));
207 RunMessageLoop();
208 EXPECT_TRUE(mock_client.get_resource_context_called());
211 class MockCanceledBeforeSentPluginProcessHostClient
212 : public MockCanceledPluginServiceClient {
213 public:
214 MockCanceledBeforeSentPluginProcessHostClient(
215 ResourceContext* context)
216 : MockCanceledPluginServiceClient(context),
217 set_plugin_info_called_(false),
218 on_found_plugin_process_host_called_(false),
219 host_(NULL) {}
221 virtual ~MockCanceledBeforeSentPluginProcessHostClient() {}
223 // Client implementation.
224 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
226 ASSERT_TRUE(info.mime_types.size());
227 ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type);
228 set_plugin_info_called_ = true;
230 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
231 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
232 set_on_found_plugin_process_host_called();
233 set_host(host);
234 // This gets called right before we request the plugin<=>renderer channel,
235 // so we have to post a task to cancel it.
236 MessageLoop::current()->PostTask(
237 FROM_HERE,
238 base::Bind(&PluginProcessHost::CancelPendingRequest,
239 base::Unretained(host), this));
240 MessageLoop::current()->PostTask(
241 FROM_HERE,
242 base::Bind(&QuitUIMessageLoopFromIOThread));
245 bool set_plugin_info_called() const {
246 return set_plugin_info_called_;
249 bool on_found_plugin_process_host_called() const {
250 return on_found_plugin_process_host_called_;
253 protected:
254 void set_on_found_plugin_process_host_called() {
255 on_found_plugin_process_host_called_ = true;
257 void set_host(PluginProcessHost* host) {
258 host_ = host;
261 PluginProcessHost* host() const { return host_; }
263 private:
264 bool set_plugin_info_called_;
265 bool on_found_plugin_process_host_called_;
266 PluginProcessHost* host_;
268 DISALLOW_COPY_AND_ASSIGN(MockCanceledBeforeSentPluginProcessHostClient);
271 IN_PROC_BROWSER_TEST_F(
272 PluginServiceTest, CancelBeforeSentOpenChannelToPluginProcessHost) {
273 ::testing::StrictMock<MockCanceledBeforeSentPluginProcessHostClient>
274 mock_client(GetResourceContext());
275 BrowserThread::PostTask(
276 BrowserThread::IO, FROM_HERE,
277 base::Bind(&OpenChannel, &mock_client));
278 RunMessageLoop();
279 EXPECT_TRUE(mock_client.get_resource_context_called());
280 EXPECT_TRUE(mock_client.set_plugin_info_called());
281 EXPECT_TRUE(mock_client.on_found_plugin_process_host_called());
284 class MockCanceledAfterSentPluginProcessHostClient
285 : public MockCanceledBeforeSentPluginProcessHostClient {
286 public:
287 MockCanceledAfterSentPluginProcessHostClient(
288 ResourceContext* context)
289 : MockCanceledBeforeSentPluginProcessHostClient(context),
290 on_sent_plugin_channel_request_called_(false) {}
291 virtual ~MockCanceledAfterSentPluginProcessHostClient() {}
293 // Client implementation.
295 virtual int ID() OVERRIDE { return 42; }
296 virtual bool OffTheRecord() OVERRIDE { return false; }
298 // We override this guy again since we don't want to cancel yet.
299 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
301 set_on_found_plugin_process_host_called();
302 set_host(host);
305 virtual void OnSentPluginChannelRequest() OVERRIDE {
306 on_sent_plugin_channel_request_called_ = true;
307 host()->CancelSentRequest(this);
308 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
309 MessageLoop::QuitClosure());
312 bool on_sent_plugin_channel_request_called() const {
313 return on_sent_plugin_channel_request_called_;
316 private:
317 bool on_sent_plugin_channel_request_called_;
319 DISALLOW_COPY_AND_ASSIGN(MockCanceledAfterSentPluginProcessHostClient);
322 // Should not attempt to open a channel, since it should be canceled early on.
323 IN_PROC_BROWSER_TEST_F(
324 PluginServiceTest, CancelAfterSentOpenChannelToPluginProcessHost) {
325 ::testing::StrictMock<MockCanceledAfterSentPluginProcessHostClient>
326 mock_client(GetResourceContext());
327 BrowserThread::PostTask(
328 BrowserThread::IO, FROM_HERE,
329 base::Bind(&OpenChannel, &mock_client));
330 RunMessageLoop();
331 EXPECT_TRUE(mock_client.get_resource_context_called());
332 EXPECT_TRUE(mock_client.set_plugin_info_called());
333 EXPECT_TRUE(mock_client.on_found_plugin_process_host_called());
334 EXPECT_TRUE(mock_client.on_sent_plugin_channel_request_called());
337 } // namespace content