OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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_service.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/command_line.h" | |
9 #include "base/path_service.h" | |
10 #include "chrome/browser/ui/browser.h" | |
11 #include "chrome/test/base/in_process_browser_test.h" | |
12 #include "chrome/test/base/testing_profile.h" | |
13 #include "chrome/test/base/ui_test_utils.h" | |
14 #include "content/browser/resource_context.h" | |
15 #include "content/public/common/content_switches.h" | |
16 #include "content/test/test_browser_thread.h" | |
17 #include "testing/gmock/include/gmock/gmock.h" | |
18 #include "webkit/plugins/npapi/plugin_list.h" | |
19 | |
20 using content::BrowserThread; | |
21 | |
22 namespace { | |
23 | |
24 const char kNPAPITestPluginMimeType[] = "application/vnd.npapi-test"; | |
25 | |
26 void OpenChannel(PluginProcessHost::Client* client) { | |
27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
28 // Start opening the channel | |
29 PluginService::GetInstance()->OpenChannelToNpapiPlugin( | |
30 0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client); | |
31 } | |
32 | |
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::Channel::Listener { | |
37 public: | |
38 MockPluginProcessHostClient(const content::ResourceContext& context) | |
39 : context_(context), | |
40 channel_(NULL), | |
41 set_plugin_info_called_(false) { | |
42 } | |
43 | |
44 virtual ~MockPluginProcessHostClient() { | |
45 if (channel_) | |
46 BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, channel_); | |
47 } | |
48 | |
49 // Client implementation. | |
50 virtual int ID() OVERRIDE { return 42; } | |
51 virtual bool OffTheRecord() OVERRIDE { return false; } | |
52 virtual const content::ResourceContext& GetResourceContext() OVERRIDE { | |
53 return context_; | |
54 } | |
55 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE {} | |
56 virtual void OnSentPluginChannelRequest() OVERRIDE {} | |
57 | |
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()); | |
64 } | |
65 | |
66 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; | |
70 } | |
71 | |
72 MOCK_METHOD0(OnError, void()); | |
73 | |
74 // Listener implementation. | |
75 MOCK_METHOD1(OnMessageReceived, bool(const IPC::Message& message)); | |
76 void OnChannelConnected(int32 peer_pid) OVERRIDE { | |
77 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
78 MessageLoop::QuitClosure()); | |
79 } | |
80 MOCK_METHOD0(OnChannelError, void()); | |
81 MOCK_METHOD0(OnChannelDenied, void()); | |
82 MOCK_METHOD0(OnChannelListenError, void()); | |
83 | |
84 private: | |
85 const content::ResourceContext& context_; | |
86 IPC::Channel* channel_; | |
87 bool set_plugin_info_called_; | |
88 DISALLOW_COPY_AND_ASSIGN(MockPluginProcessHostClient); | |
89 }; | |
90 | |
91 class PluginServiceTest : public InProcessBrowserTest { | |
92 public: | |
93 PluginServiceTest() : InProcessBrowserTest() { } | |
94 | |
95 virtual void SetUpCommandLine(CommandLine* command_line) { | |
96 #ifdef OS_MACOSX | |
97 FilePath browser_directory; | |
98 PathService::Get(base::DIR_MODULE, &browser_directory); | |
99 command_line->AppendSwitchPath(switches::kExtraPluginDir, | |
100 browser_directory.AppendASCII("plugins")); | |
101 #endif | |
102 } | |
103 }; | |
104 | |
105 // Try to open a channel to the test plugin. Minimal plugin process spawning | |
106 // test for the PluginService interface. | |
107 IN_PROC_BROWSER_TEST_F(PluginServiceTest, OpenChannelToPlugin) { | |
108 ::testing::StrictMock<MockPluginProcessHostClient> mock_client( | |
109 browser()->profile()->GetResourceContext()); | |
110 BrowserThread::PostTask( | |
111 BrowserThread::IO, FROM_HERE, | |
112 base::Bind(&OpenChannel, &mock_client)); | |
113 ui_test_utils::RunMessageLoop(); | |
114 } | |
115 | |
116 // A strict mock that fails if any of the methods are called. They shouldn't be | |
117 // called since the request should get canceled before then. | |
118 class MockCanceledPluginServiceClient : public PluginProcessHost::Client { | |
119 public: | |
120 MockCanceledPluginServiceClient(const content::ResourceContext& context) | |
121 : context_(context), | |
122 get_resource_context_called_(false) { | |
123 } | |
124 | |
125 virtual ~MockCanceledPluginServiceClient() {} | |
126 | |
127 // Client implementation. | |
128 MOCK_METHOD0(ID, int()); | |
129 virtual const content::ResourceContext& GetResourceContext() OVERRIDE { | |
130 get_resource_context_called_ = true; | |
131 return context_; | |
132 } | |
133 MOCK_METHOD0(OffTheRecord, bool()); | |
134 MOCK_METHOD1(OnFoundPluginProcessHost, void(PluginProcessHost* host)); | |
135 MOCK_METHOD0(OnSentPluginChannelRequest, void()); | |
136 MOCK_METHOD1(OnChannelOpened, void(const IPC::ChannelHandle& handle)); | |
137 MOCK_METHOD1(SetPluginInfo, void(const webkit::WebPluginInfo& info)); | |
138 MOCK_METHOD0(OnError, void()); | |
139 | |
140 bool get_resource_context_called() const { | |
141 return get_resource_context_called_; | |
142 } | |
143 | |
144 private: | |
145 const content::ResourceContext& context_; | |
146 bool get_resource_context_called_; | |
147 | |
148 DISALLOW_COPY_AND_ASSIGN(MockCanceledPluginServiceClient); | |
149 }; | |
150 | |
151 void DoNothing() {} | |
152 | |
153 void QuitUIMessageLoopFromIOThread() { | |
154 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
155 MessageLoop::QuitClosure()); | |
156 } | |
157 | |
158 void OpenChannelAndThenCancel(PluginProcessHost::Client* client) { | |
159 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
160 // Start opening the channel | |
161 PluginService::GetInstance()->OpenChannelToNpapiPlugin( | |
162 0, 0, GURL(), GURL(), kNPAPITestPluginMimeType, client); | |
163 // Immediately cancel it. This is guaranteed to work since PluginService needs | |
164 // to consult its filter on the FILE thread. | |
165 PluginService::GetInstance()->CancelOpenChannelToNpapiPlugin(client); | |
166 // Before we terminate the test, add a roundtrip through the FILE thread to | |
167 // make sure that it's had a chance to post back to the IO thread. Then signal | |
168 // the UI thread to stop and exit the test. | |
169 BrowserThread::PostTaskAndReply( | |
170 BrowserThread::FILE, FROM_HERE, | |
171 base::Bind(&DoNothing), | |
172 base::Bind(&QuitUIMessageLoopFromIOThread)); | |
173 } | |
174 | |
175 // Should not attempt to open a channel, since it should be canceled early on. | |
176 IN_PROC_BROWSER_TEST_F(PluginServiceTest, CancelOpenChannelToPluginService) { | |
177 ::testing::StrictMock<MockCanceledPluginServiceClient> mock_client( | |
178 browser()->profile()->GetResourceContext()); | |
179 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
180 base::Bind(OpenChannelAndThenCancel, &mock_client)); | |
181 ui_test_utils::RunMessageLoop(); | |
182 EXPECT_TRUE(mock_client.get_resource_context_called()); | |
183 } | |
184 | |
185 class MockCanceledBeforeSentPluginProcessHostClient | |
186 : public MockCanceledPluginServiceClient { | |
187 public: | |
188 MockCanceledBeforeSentPluginProcessHostClient( | |
189 const content::ResourceContext& context) | |
190 : MockCanceledPluginServiceClient(context), | |
191 set_plugin_info_called_(false), | |
192 on_found_plugin_process_host_called_(false), | |
193 host_(NULL) {} | |
194 | |
195 virtual ~MockCanceledBeforeSentPluginProcessHostClient() {} | |
196 | |
197 // Client implementation. | |
198 virtual void SetPluginInfo(const webkit::WebPluginInfo& info) OVERRIDE { | |
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
200 ASSERT_TRUE(info.mime_types.size()); | |
201 ASSERT_EQ(kNPAPITestPluginMimeType, info.mime_types[0].mime_type); | |
202 set_plugin_info_called_ = true; | |
203 } | |
204 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE { | |
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
206 set_on_found_plugin_process_host_called(); | |
207 set_host(host); | |
208 // This gets called right before we request the plugin<=>renderer channel, | |
209 // so we have to post a task to cancel it. | |
210 MessageLoop::current()->PostTask( | |
211 FROM_HERE, | |
212 base::Bind(&PluginProcessHost::CancelPendingRequest, | |
213 base::Unretained(host), this)); | |
214 MessageLoop::current()->PostTask( | |
215 FROM_HERE, | |
216 base::Bind(&QuitUIMessageLoopFromIOThread)); | |
217 } | |
218 | |
219 bool set_plugin_info_called() const { | |
220 return set_plugin_info_called_; | |
221 } | |
222 | |
223 bool on_found_plugin_process_host_called() const { | |
224 return on_found_plugin_process_host_called_; | |
225 } | |
226 | |
227 protected: | |
228 void set_on_found_plugin_process_host_called() { | |
229 on_found_plugin_process_host_called_ = true; | |
230 } | |
231 void set_host(PluginProcessHost* host) { | |
232 host_ = host; | |
233 } | |
234 | |
235 PluginProcessHost* host() const { return host_; } | |
236 | |
237 private: | |
238 bool set_plugin_info_called_; | |
239 bool on_found_plugin_process_host_called_; | |
240 PluginProcessHost* host_; | |
241 | |
242 DISALLOW_COPY_AND_ASSIGN(MockCanceledBeforeSentPluginProcessHostClient); | |
243 }; | |
244 | |
245 IN_PROC_BROWSER_TEST_F( | |
246 PluginServiceTest, CancelBeforeSentOpenChannelToPluginProcessHost) { | |
247 ::testing::StrictMock<MockCanceledBeforeSentPluginProcessHostClient> | |
248 mock_client(browser()->profile()->GetResourceContext()); | |
249 BrowserThread::PostTask( | |
250 BrowserThread::IO, FROM_HERE, | |
251 base::Bind(&OpenChannel, &mock_client)); | |
252 ui_test_utils::RunMessageLoop(); | |
253 EXPECT_TRUE(mock_client.get_resource_context_called()); | |
254 EXPECT_TRUE(mock_client.set_plugin_info_called()); | |
255 EXPECT_TRUE(mock_client.on_found_plugin_process_host_called()); | |
256 } | |
257 | |
258 class MockCanceledAfterSentPluginProcessHostClient | |
259 : public MockCanceledBeforeSentPluginProcessHostClient { | |
260 public: | |
261 MockCanceledAfterSentPluginProcessHostClient( | |
262 const content::ResourceContext& context) | |
263 : MockCanceledBeforeSentPluginProcessHostClient(context), | |
264 on_sent_plugin_channel_request_called_(false) {} | |
265 virtual ~MockCanceledAfterSentPluginProcessHostClient() {} | |
266 | |
267 // Client implementation. | |
268 | |
269 virtual int ID() OVERRIDE { return 42; } | |
270 virtual bool OffTheRecord() OVERRIDE { return false; } | |
271 | |
272 // We override this guy again since we don't want to cancel yet. | |
273 virtual void OnFoundPluginProcessHost(PluginProcessHost* host) OVERRIDE { | |
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
275 set_on_found_plugin_process_host_called(); | |
276 set_host(host); | |
277 } | |
278 | |
279 virtual void OnSentPluginChannelRequest() OVERRIDE { | |
280 on_sent_plugin_channel_request_called_ = true; | |
281 host()->CancelSentRequest(this); | |
282 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
283 MessageLoop::QuitClosure()); | |
284 } | |
285 | |
286 bool on_sent_plugin_channel_request_called() const { | |
287 return on_sent_plugin_channel_request_called_; | |
288 } | |
289 | |
290 private: | |
291 bool on_sent_plugin_channel_request_called_; | |
292 | |
293 DISALLOW_COPY_AND_ASSIGN(MockCanceledAfterSentPluginProcessHostClient); | |
294 }; | |
295 | |
296 // Should not attempt to open a channel, since it should be canceled early on. | |
297 IN_PROC_BROWSER_TEST_F( | |
298 PluginServiceTest, CancelAfterSentOpenChannelToPluginProcessHost) { | |
299 ::testing::StrictMock<MockCanceledAfterSentPluginProcessHostClient> | |
300 mock_client(browser()->profile()->GetResourceContext()); | |
301 BrowserThread::PostTask( | |
302 BrowserThread::IO, FROM_HERE, | |
303 base::Bind(&OpenChannel, &mock_client)); | |
304 ui_test_utils::RunMessageLoop(); | |
305 EXPECT_TRUE(mock_client.get_resource_context_called()); | |
306 EXPECT_TRUE(mock_client.set_plugin_info_called()); | |
307 EXPECT_TRUE(mock_client.on_found_plugin_process_host_called()); | |
308 EXPECT_TRUE(mock_client.on_sent_plugin_channel_request_called()); | |
309 } | |
310 | |
311 } // namespace | |
OLD | NEW |