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 "chrome/test/ppapi/ppapi_test.h"
6
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/path_service.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/content_settings/host_content_settings_map.h"
14 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
15 #include "chrome/browser/infobars/infobar.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/test/base/test_switches.h"
22 #include "chrome/test/base/ui_test_utils.h"
23 #include "content/public/browser/dom_operation_notification_details.h"
24 #include "content/public/browser/notification_service.h"
25 #include "content/public/browser/web_contents.h"
26 #include "net/base/net_util.h"
27 #include "net/base/test_data_directory.h"
28 #include "ppapi/shared_impl/ppapi_switches.h"
29 #include "ui/gl/gl_switches.h"
30
31 using content::DomOperationNotificationDetails;
32 using content::RenderViewHost;
33
34 namespace {
35
36 // Platform-specific filename relative to the chrome executable.
37 #if defined(OS_WIN)
38 const wchar_t library_name[] = L"ppapi_tests.dll";
39 #elif defined(OS_MACOSX)
40 const char library_name[] = "ppapi_tests.plugin";
41 #elif defined(OS_POSIX)
42 const char library_name[] = "libppapi_tests.so";
43 #endif
44
45 } // namespace
46
PPAPITestMessageHandler()47 PPAPITestMessageHandler::PPAPITestMessageHandler() {
48 }
49
HandleMessage(const std::string & json)50 TestMessageHandler::MessageResponse PPAPITestMessageHandler::HandleMessage(
51 const std::string& json) {
52 std::string trimmed;
53 base::TrimString(json, "\"", &trimmed);
54 if (trimmed == "...")
55 return CONTINUE;
56 message_ = trimmed;
57 return DONE;
58 }
59
Reset()60 void PPAPITestMessageHandler::Reset() {
61 TestMessageHandler::Reset();
62 message_.clear();
63 }
64
InfoBarObserver(PPAPITestBase * test_base)65 PPAPITestBase::InfoBarObserver::InfoBarObserver(PPAPITestBase* test_base)
66 : test_base_(test_base),
67 expecting_infobar_(false),
68 should_accept_(false) {
69 registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
70 content::NotificationService::AllSources());
71 }
72
~InfoBarObserver()73 PPAPITestBase::InfoBarObserver::~InfoBarObserver() {
74 EXPECT_FALSE(expecting_infobar_) << "Missing an expected infobar";
75 }
76
ExpectInfoBarAndAccept(bool should_accept)77 void PPAPITestBase::InfoBarObserver::ExpectInfoBarAndAccept(
78 bool should_accept) {
79 ASSERT_FALSE(expecting_infobar_);
80 expecting_infobar_ = true;
81 should_accept_ = should_accept;
82 }
83
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)84 void PPAPITestBase::InfoBarObserver::Observe(
85 int type,
86 const content::NotificationSource& source,
87 const content::NotificationDetails& details) {
88 ASSERT_EQ(chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, type);
89 // It's not safe to remove the infobar here, since other observers (e.g. the
90 // InfoBarContainer) may still need to access it. Instead, post a task to
91 // do all necessary infobar manipulation as soon as this call stack returns.
92 base::MessageLoop::current()->PostTask(
93 FROM_HERE, base::Bind(&InfoBarObserver::VerifyInfoBarState,
94 base::Unretained(this)));
95 }
96
VerifyInfoBarState()97 void PPAPITestBase::InfoBarObserver::VerifyInfoBarState() {
98 content::WebContents* web_contents =
99 test_base_->browser()->tab_strip_model()->GetActiveWebContents();
100 ASSERT_TRUE(web_contents != NULL);
101 InfoBarService* infobar_service =
102 InfoBarService::FromWebContents(web_contents);
103 ASSERT_TRUE(infobar_service != NULL);
104
105 EXPECT_EQ(expecting_infobar_ ? 1U : 0U, infobar_service->infobar_count());
106 if (!expecting_infobar_)
107 return;
108 expecting_infobar_ = false;
109
110 InfoBar* infobar = infobar_service->infobar_at(0);
111 ConfirmInfoBarDelegate* delegate =
112 infobar->delegate()->AsConfirmInfoBarDelegate();
113 ASSERT_TRUE(delegate != NULL);
114 if (should_accept_)
115 delegate->Accept();
116 else
117 delegate->Cancel();
118
119 infobar_service->RemoveInfoBar(infobar);
120 }
121
PPAPITestBase()122 PPAPITestBase::PPAPITestBase() {
123 }
124
SetUpCommandLine(CommandLine * command_line)125 void PPAPITestBase::SetUpCommandLine(CommandLine* command_line) {
126 // The test sends us the result via a cookie.
127 command_line->AppendSwitch(switches::kEnableFileCookies);
128
129 // Some stuff is hung off of the testing interface which is not enabled
130 // by default.
131 command_line->AppendSwitch(switches::kEnablePepperTesting);
132
133 // Smooth scrolling confuses the scrollbar test.
134 command_line->AppendSwitch(switches::kDisableSmoothScrolling);
135
136 // For TestRequestOSFileHandle.
137 command_line->AppendSwitch(switches::kUnlimitedStorage);
138 command_line->AppendSwitchASCII(switches::kAllowNaClFileHandleAPI,
139 "127.0.0.1");
140 }
141
SetUpOnMainThread()142 void PPAPITestBase::SetUpOnMainThread() {
143 // Always allow access to the PPAPI broker.
144 browser()->profile()->GetHostContentSettingsMap()->SetDefaultContentSetting(
145 CONTENT_SETTINGS_TYPE_PPAPI_BROKER, CONTENT_SETTING_ALLOW);
146 }
147
GetTestFileUrl(const std::string & test_case)148 GURL PPAPITestBase::GetTestFileUrl(const std::string& test_case) {
149 base::FilePath test_path;
150 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_path));
151 test_path = test_path.Append(FILE_PATH_LITERAL("ppapi"));
152 test_path = test_path.Append(FILE_PATH_LITERAL("tests"));
153 test_path = test_path.Append(FILE_PATH_LITERAL("test_case.html"));
154
155 // Sanity check the file name.
156 EXPECT_TRUE(base::PathExists(test_path));
157
158 GURL test_url = net::FilePathToFileURL(test_path);
159
160 GURL::Replacements replacements;
161 std::string query = BuildQuery(std::string(), test_case);
162 replacements.SetQuery(query.c_str(), url_parse::Component(0, query.size()));
163 return test_url.ReplaceComponents(replacements);
164 }
165
RunTest(const std::string & test_case)166 void PPAPITestBase::RunTest(const std::string& test_case) {
167 GURL url = GetTestFileUrl(test_case);
168 RunTestURL(url);
169 }
170
RunTestAndReload(const std::string & test_case)171 void PPAPITestBase::RunTestAndReload(const std::string& test_case) {
172 GURL url = GetTestFileUrl(test_case);
173 RunTestURL(url);
174 // If that passed, we simply run the test again, which navigates again.
175 RunTestURL(url);
176 }
177
RunTestViaHTTP(const std::string & test_case)178 void PPAPITestBase::RunTestViaHTTP(const std::string& test_case) {
179 base::FilePath document_root;
180 ASSERT_TRUE(ui_test_utils::GetRelativeBuildDirectory(&document_root));
181 base::FilePath http_document_root;
182 ASSERT_TRUE(ui_test_utils::GetRelativeBuildDirectory(&http_document_root));
183 net::SpawnedTestServer http_server(net::SpawnedTestServer::TYPE_HTTP,
184 net::SpawnedTestServer::kLocalhost,
185 document_root);
186 ASSERT_TRUE(http_server.Start());
187 RunTestURL(GetTestURL(http_server, test_case, std::string()));
188 }
189
RunTestWithSSLServer(const std::string & test_case)190 void PPAPITestBase::RunTestWithSSLServer(const std::string& test_case) {
191 base::FilePath http_document_root;
192 ASSERT_TRUE(ui_test_utils::GetRelativeBuildDirectory(&http_document_root));
193 net::SpawnedTestServer http_server(net::SpawnedTestServer::TYPE_HTTP,
194 net::SpawnedTestServer::kLocalhost,
195 http_document_root);
196 net::SpawnedTestServer ssl_server(net::SpawnedTestServer::TYPE_HTTPS,
197 net::BaseTestServer::SSLOptions(),
198 http_document_root);
199 // Start the servers in parallel.
200 ASSERT_TRUE(http_server.StartInBackground());
201 ASSERT_TRUE(ssl_server.StartInBackground());
202 // Wait until they are both finished before continuing.
203 ASSERT_TRUE(http_server.BlockUntilStarted());
204 ASSERT_TRUE(ssl_server.BlockUntilStarted());
205
206 uint16_t port = ssl_server.host_port_pair().port();
207 RunTestURL(GetTestURL(http_server,
208 test_case,
209 base::StringPrintf("ssl_server_port=%d", port)));
210 }
211
RunTestWithWebSocketServer(const std::string & test_case)212 void PPAPITestBase::RunTestWithWebSocketServer(const std::string& test_case) {
213 base::FilePath http_document_root;
214 ASSERT_TRUE(ui_test_utils::GetRelativeBuildDirectory(&http_document_root));
215 net::SpawnedTestServer http_server(net::SpawnedTestServer::TYPE_HTTP,
216 net::SpawnedTestServer::kLocalhost,
217 http_document_root);
218 net::SpawnedTestServer ws_server(net::SpawnedTestServer::TYPE_WS,
219 net::SpawnedTestServer::kLocalhost,
220 net::GetWebSocketTestDataDirectory());
221 // Start the servers in parallel.
222 ASSERT_TRUE(http_server.StartInBackground());
223 ASSERT_TRUE(ws_server.StartInBackground());
224 // Wait until they are both finished before continuing.
225 ASSERT_TRUE(http_server.BlockUntilStarted());
226 ASSERT_TRUE(ws_server.BlockUntilStarted());
227
228 std::string host = ws_server.host_port_pair().HostForURL();
229 uint16_t port = ws_server.host_port_pair().port();
230 RunTestURL(GetTestURL(http_server,
231 test_case,
232 base::StringPrintf(
233 "websocket_host=%s&websocket_port=%d",
234 host.c_str(),
235 port)));
236 }
237
RunTestIfAudioOutputAvailable(const std::string & test_case)238 void PPAPITestBase::RunTestIfAudioOutputAvailable(
239 const std::string& test_case) {
240 RunTest(test_case);
241 }
242
RunTestViaHTTPIfAudioOutputAvailable(const std::string & test_case)243 void PPAPITestBase::RunTestViaHTTPIfAudioOutputAvailable(
244 const std::string& test_case) {
245 RunTestViaHTTP(test_case);
246 }
247
StripPrefixes(const std::string & test_name)248 std::string PPAPITestBase::StripPrefixes(const std::string& test_name) {
249 const char* const prefixes[] = {
250 "FAILS_", "FLAKY_", "DISABLED_", "SLOW_" };
251 for (size_t i = 0; i < sizeof(prefixes)/sizeof(prefixes[0]); ++i)
252 if (test_name.find(prefixes[i]) == 0)
253 return test_name.substr(strlen(prefixes[i]));
254 return test_name;
255 }
256
RunTestURL(const GURL & test_url)257 void PPAPITestBase::RunTestURL(const GURL& test_url) {
258 #if defined(OS_WIN) && defined(USE_ASH)
259 // PPAPITests are broken in Ash browser tests (http://crbug.com/263548).
260 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) {
261 LOG(WARNING) << "PPAPITests are disabled for Ash browser tests.";
262 return;
263 }
264 #endif
265
266 // See comment above TestingInstance in ppapi/test/testing_instance.h.
267 // Basically it sends messages using the DOM automation controller. The
268 // value of "..." means it's still working and we should continue to wait,
269 // any other value indicates completion (in this case it will start with
270 // "PASS" or "FAIL"). This keeps us from timing out on waits for long tests.
271 PPAPITestMessageHandler handler;
272 JavascriptTestObserver observer(
273 browser()->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
274 &handler);
275
276 ui_test_utils::NavigateToURL(browser(), test_url);
277
278 ASSERT_TRUE(observer.Run()) << handler.error_message();
279 EXPECT_STREQ("PASS", handler.message().c_str());
280 }
281
GetTestURL(const net::SpawnedTestServer & http_server,const std::string & test_case,const std::string & extra_params)282 GURL PPAPITestBase::GetTestURL(
283 const net::SpawnedTestServer& http_server,
284 const std::string& test_case,
285 const std::string& extra_params) {
286 std::string query = BuildQuery("files/test_case.html?", test_case);
287 if (!extra_params.empty())
288 query = base::StringPrintf("%s&%s", query.c_str(), extra_params.c_str());
289
290 return http_server.GetURL(query);
291 }
292
PPAPITest()293 PPAPITest::PPAPITest() : in_process_(true) {
294 }
295
SetUpCommandLine(CommandLine * command_line)296 void PPAPITest::SetUpCommandLine(CommandLine* command_line) {
297 PPAPITestBase::SetUpCommandLine(command_line);
298
299 // Append the switch to register the pepper plugin.
300 // library name = <out dir>/<test_name>.<library_extension>
301 // MIME type = application/x-ppapi-<test_name>
302 base::FilePath plugin_dir;
303 EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &plugin_dir));
304
305 base::FilePath plugin_lib = plugin_dir.Append(library_name);
306 EXPECT_TRUE(base::PathExists(plugin_lib));
307 base::FilePath::StringType pepper_plugin = plugin_lib.value();
308 pepper_plugin.append(FILE_PATH_LITERAL(";application/x-ppapi-tests"));
309 command_line->AppendSwitchNative(switches::kRegisterPepperPlugins,
310 pepper_plugin);
311 command_line->AppendSwitchASCII(switches::kAllowNaClSocketAPI, "127.0.0.1");
312
313 if (in_process_)
314 command_line->AppendSwitch(switches::kPpapiInProcess);
315 }
316
BuildQuery(const std::string & base,const std::string & test_case)317 std::string PPAPITest::BuildQuery(const std::string& base,
318 const std::string& test_case){
319 return base::StringPrintf("%stestcase=%s", base.c_str(), test_case.c_str());
320 }
321
OutOfProcessPPAPITest()322 OutOfProcessPPAPITest::OutOfProcessPPAPITest() {
323 in_process_ = false;
324 }
325
SetUpCommandLine(CommandLine * command_line)326 void OutOfProcessPPAPITest::SetUpCommandLine(CommandLine* command_line) {
327 PPAPITest::SetUpCommandLine(command_line);
328 command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
329 command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
330 }
331
SetUpCommandLine(CommandLine * command_line)332 void PPAPINaClTest::SetUpCommandLine(CommandLine* command_line) {
333 PPAPITestBase::SetUpCommandLine(command_line);
334
335 base::FilePath plugin_lib;
336 EXPECT_TRUE(PathService::Get(chrome::FILE_NACL_PLUGIN, &plugin_lib));
337 EXPECT_TRUE(base::PathExists(plugin_lib));
338
339 // Enable running (non-portable) NaCl outside of the Chrome web store.
340 command_line->AppendSwitch(switches::kEnableNaCl);
341 command_line->AppendSwitchASCII(switches::kAllowNaClSocketAPI, "127.0.0.1");
342 command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
343 command_line->AppendSwitch(switches::kUseFakeUIForMediaStream);
344 }
345
346 // Append the correct mode and testcase string
BuildQuery(const std::string & base,const std::string & test_case)347 std::string PPAPINaClNewlibTest::BuildQuery(const std::string& base,
348 const std::string& test_case) {
349 return base::StringPrintf("%smode=nacl_newlib&testcase=%s", base.c_str(),
350 test_case.c_str());
351 }
352
353 // Append the correct mode and testcase string
BuildQuery(const std::string & base,const std::string & test_case)354 std::string PPAPINaClGLibcTest::BuildQuery(const std::string& base,
355 const std::string& test_case) {
356 return base::StringPrintf("%smode=nacl_glibc&testcase=%s", base.c_str(),
357 test_case.c_str());
358 }
359
360 // Append the correct mode and testcase string
BuildQuery(const std::string & base,const std::string & test_case)361 std::string PPAPINaClPNaClTest::BuildQuery(const std::string& base,
362 const std::string& test_case) {
363 return base::StringPrintf("%smode=nacl_pnacl&testcase=%s", base.c_str(),
364 test_case.c_str());
365 }
366
SetUpCommandLine(CommandLine * command_line)367 void PPAPINaClTestDisallowedSockets::SetUpCommandLine(
368 CommandLine* command_line) {
369 PPAPITestBase::SetUpCommandLine(command_line);
370
371 base::FilePath plugin_lib;
372 EXPECT_TRUE(PathService::Get(chrome::FILE_NACL_PLUGIN, &plugin_lib));
373 EXPECT_TRUE(base::PathExists(plugin_lib));
374
375 // Enable running (non-portable) NaCl outside of the Chrome web store.
376 command_line->AppendSwitch(switches::kEnableNaCl);
377 }
378
379 // Append the correct mode and testcase string
BuildQuery(const std::string & base,const std::string & test_case)380 std::string PPAPINaClTestDisallowedSockets::BuildQuery(
381 const std::string& base,
382 const std::string& test_case) {
383 return base::StringPrintf("%smode=nacl_newlib&testcase=%s", base.c_str(),
384 test_case.c_str());
385 }
386
SetUpOnMainThread()387 void PPAPIBrokerInfoBarTest::SetUpOnMainThread() {
388 // The default content setting for the PPAPI broker is ASK. We purposefully
389 // don't call PPAPITestBase::SetUpOnMainThread() to keep it that way.
390 }
391