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