Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / test / nacl / nacl_browsertest_util.cc
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/nacl/nacl_browsertest_util.h"
6
7 #include <stdlib.h>
8 #include "base/command_line.h"
9 #include "base/json/json_reader.h"
10 #include "base/path_service.h"
11 #include "base/values.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/common/chrome_paths.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "components/nacl/common/nacl_switches.h"
18 #include "content/public/browser/plugin_service.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/common/webplugininfo.h"
21 #include "net/base/net_util.h"
22
23 typedef content::TestMessageHandler::MessageResponse MessageResponse;
24
25 MessageResponse StructuredMessageHandler::HandleMessage(
26     const std::string& json) {
27   scoped_ptr<base::Value> value;
28   base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
29   // Automation messages are stringified before they are sent because the
30   // automation channel cannot handle arbitrary objects.  This means we
31   // need to decode the json twice to get the original message.
32   value.reset(reader.ReadToValue(json));
33   if (!value.get())
34     return InternalError("Could parse automation JSON: " + json +
35                          " because " + reader.GetErrorMessage());
36
37   std::string temp;
38   if (!value->GetAsString(&temp))
39     return InternalError("Message was not a string: " + json);
40
41   value.reset(reader.ReadToValue(temp));
42   if (!value.get())
43     return InternalError("Could not parse message JSON: " + temp +
44                          " because " + reader.GetErrorMessage());
45
46   base::DictionaryValue* msg;
47   if (!value->GetAsDictionary(&msg))
48     return InternalError("Message was not an object: " + temp);
49
50   std::string type;
51   if (!msg->GetString("type", &type))
52     return MissingField("unknown", "type");
53
54   return HandleStructuredMessage(type, msg);
55 }
56
57 MessageResponse StructuredMessageHandler::MissingField(
58     const std::string& type,
59     const std::string& field) {
60   return InternalError(type + " message did not have field: " + field);
61 }
62
63 MessageResponse StructuredMessageHandler::InternalError(
64     const std::string& reason) {
65   SetError(reason);
66   return DONE;
67 }
68
69 LoadTestMessageHandler::LoadTestMessageHandler()
70     : test_passed_(false) {
71 }
72
73 void LoadTestMessageHandler::Log(const std::string& type,
74                                  const std::string& message) {
75   // TODO(ncbray) better logging.
76   LOG(INFO) << type << " " << message;
77 }
78
79 MessageResponse LoadTestMessageHandler::HandleStructuredMessage(
80    const std::string& type,
81    base::DictionaryValue* msg) {
82   if (type == "Log") {
83     std::string message;
84     if (!msg->GetString("message", &message))
85       return MissingField(type, "message");
86     Log("LOG", message);
87     return CONTINUE;
88   } else if (type == "Shutdown") {
89     std::string message;
90     if (!msg->GetString("message", &message))
91       return MissingField(type, "message");
92     if (!msg->GetBoolean("passed", &test_passed_))
93       return MissingField(type, "passed");
94     Log("SHUTDOWN", message);
95     return DONE;
96   } else {
97     return InternalError("Unknown message type: " + type);
98   }
99 }
100
101 // A message handler for nacl_integration tests ported to be browser_tests.
102 // nacl_integration tests report to their test jig using a series of RPC calls
103 // that are encoded as URL requests. When these tests run as browser_tests,
104 // they make the same RPC requests, but use the automation channel instead of
105 // URL requests. This message handler decodes and responds to these requests.
106 class NaClIntegrationMessageHandler : public StructuredMessageHandler {
107  public:
108   NaClIntegrationMessageHandler();
109
110   void Log(const std::string& message);
111
112   MessageResponse HandleStructuredMessage(const std::string& type,
113                                           base::DictionaryValue* msg) override;
114
115   bool test_passed() const {
116     return test_passed_;
117   }
118
119  private:
120   bool test_passed_;
121
122   DISALLOW_COPY_AND_ASSIGN(NaClIntegrationMessageHandler);
123 };
124
125 NaClIntegrationMessageHandler::NaClIntegrationMessageHandler()
126     : test_passed_(false) {
127 }
128
129 void NaClIntegrationMessageHandler::Log(const std::string& message) {
130   // TODO(ncbray) better logging.
131   LOG(INFO) << "|||| " << message;
132 }
133
134 MessageResponse NaClIntegrationMessageHandler::HandleStructuredMessage(
135     const std::string& type,
136     base::DictionaryValue* msg) {
137   if (type == "TestLog") {
138     std::string message;
139     if (!msg->GetString("message", &message))
140       return MissingField(type, "message");
141     Log(message);
142     return CONTINUE;
143   } else if (type == "Shutdown") {
144     std::string message;
145     if (!msg->GetString("message", &message))
146       return MissingField(type, "message");
147     if (!msg->GetBoolean("passed", &test_passed_))
148       return MissingField(type, "passed");
149     Log(message);
150     return DONE;
151   } else if (type == "Ping") {
152     return CONTINUE;
153   } else if (type == "JavaScriptIsAlive") {
154     return CONTINUE;
155   } else {
156     return InternalError("Unknown message type: " + type);
157   }
158 }
159
160 // NaCl browser tests serve files out of the build directory because nexes and
161 // pexes are artifacts of the build.  To keep things tidy, all test data is kept
162 // in a subdirectory.  Several variants of a test may be run, for example when
163 // linked against newlib and when linked against glibc.  These variants are kept
164 // in different subdirectories.  For example, the build directory will look
165 // something like this on Linux:
166 // out/
167 //     Release/
168 //             nacl_test_data/
169 //                            newlib/
170 //                            glibc/
171 //                            pnacl/
172 static bool GetNaClVariantRoot(const base::FilePath::StringType& variant,
173                                base::FilePath* document_root) {
174   if (!ui_test_utils::GetRelativeBuildDirectory(document_root))
175     return false;
176   *document_root = document_root->Append(FILE_PATH_LITERAL("nacl_test_data"));
177   *document_root = document_root->Append(variant);
178   return true;
179 }
180
181 static void AddPnaclParm(const base::FilePath::StringType& url,
182                          base::FilePath::StringType* url_with_parm) {
183   if (url.find(FILE_PATH_LITERAL("?")) == base::FilePath::StringType::npos) {
184     *url_with_parm = url + FILE_PATH_LITERAL("?pnacl=1");
185   } else {
186     *url_with_parm = url + FILE_PATH_LITERAL("&pnacl=1");
187   }
188 }
189
190 NaClBrowserTestBase::NaClBrowserTestBase() {
191 }
192
193 NaClBrowserTestBase::~NaClBrowserTestBase() {
194 }
195
196 void NaClBrowserTestBase::SetUpCommandLine(base::CommandLine* command_line) {
197   command_line->AppendSwitch(switches::kEnableNaCl);
198 }
199
200 void NaClBrowserTestBase::SetUpOnMainThread() {
201   ASSERT_TRUE(StartTestServer()) << "Cannot start test server.";
202 }
203
204 bool NaClBrowserTestBase::GetDocumentRoot(base::FilePath* document_root) {
205   return GetNaClVariantRoot(Variant(), document_root);
206 }
207
208 bool NaClBrowserTestBase::IsAPnaclTest() {
209   return false;
210 }
211
212 GURL NaClBrowserTestBase::TestURL(
213     const base::FilePath::StringType& url_fragment) {
214   base::FilePath expanded_url = base::FilePath(FILE_PATH_LITERAL("files"));
215   expanded_url = expanded_url.Append(url_fragment);
216   return test_server_->GetURL(expanded_url.MaybeAsASCII());
217 }
218
219 bool NaClBrowserTestBase::RunJavascriptTest(
220     const GURL& url,
221     content::TestMessageHandler* handler) {
222   content::JavascriptTestObserver observer(
223       browser()->tab_strip_model()->GetActiveWebContents(),
224       handler);
225   ui_test_utils::NavigateToURL(browser(), url);
226   return observer.Run();
227 }
228
229 void NaClBrowserTestBase::RunLoadTest(
230     const base::FilePath::StringType& test_file) {
231   LoadTestMessageHandler handler;
232   base::FilePath::StringType test_file_with_pnacl = test_file;
233   if (IsAPnaclTest()) {
234     AddPnaclParm(test_file, &test_file_with_pnacl);
235   }
236   base::FilePath::StringType test_file_with_both = test_file_with_pnacl;
237   bool ok = RunJavascriptTest(TestURL(test_file_with_both), &handler);
238   ASSERT_TRUE(ok) << handler.error_message();
239   ASSERT_TRUE(handler.test_passed()) << "Test failed.";
240 }
241
242 void NaClBrowserTestBase::RunNaClIntegrationTest(
243     const base::FilePath::StringType& url_fragment, bool full_url) {
244   NaClIntegrationMessageHandler handler;
245   base::FilePath::StringType url_fragment_with_pnacl = url_fragment;
246   if (IsAPnaclTest()) {
247     AddPnaclParm(url_fragment, &url_fragment_with_pnacl);
248   }
249   base::FilePath::StringType url_fragment_with_both = url_fragment_with_pnacl;
250   bool ok = RunJavascriptTest(full_url
251                               ? GURL(url_fragment_with_both)
252                               : TestURL(url_fragment_with_both),
253                               &handler);
254   ASSERT_TRUE(ok) << handler.error_message();
255   ASSERT_TRUE(handler.test_passed()) << "Test failed.";
256 }
257
258 bool NaClBrowserTestBase::StartTestServer() {
259   // Launch the web server.
260   base::FilePath document_root;
261   if (!GetDocumentRoot(&document_root))
262     return false;
263   test_server_.reset(new net::SpawnedTestServer(
264                          net::SpawnedTestServer::TYPE_HTTP,
265                          net::SpawnedTestServer::kLocalhost,
266                          document_root));
267   return test_server_->Start();
268 }
269
270 base::FilePath::StringType NaClBrowserTestNewlib::Variant() {
271   return FILE_PATH_LITERAL("newlib");
272 }
273
274 base::FilePath::StringType NaClBrowserTestGLibc::Variant() {
275   return FILE_PATH_LITERAL("glibc");
276 }
277
278 base::FilePath::StringType NaClBrowserTestPnacl::Variant() {
279   return FILE_PATH_LITERAL("pnacl");
280 }
281
282 bool NaClBrowserTestPnacl::IsAPnaclTest() {
283   return true;
284 }
285
286 base::FilePath::StringType NaClBrowserTestNonSfiMode::Variant() {
287   return FILE_PATH_LITERAL("libc-free");
288 }
289
290 void NaClBrowserTestNonSfiMode::SetUpCommandLine(
291     base::CommandLine* command_line) {
292   NaClBrowserTestBase::SetUpCommandLine(command_line);
293   command_line->AppendSwitch(switches::kEnableNaClNonSfiMode);
294 }
295
296 base::FilePath::StringType NaClBrowserTestStatic::Variant() {
297   return FILE_PATH_LITERAL("static");
298 }
299
300 bool NaClBrowserTestStatic::GetDocumentRoot(base::FilePath* document_root) {
301   *document_root = base::FilePath(FILE_PATH_LITERAL("chrome/test/data/nacl"));
302   return true;
303 }
304
305 base::FilePath::StringType NaClBrowserTestPnaclNonSfi::Variant() {
306   return FILE_PATH_LITERAL("nonsfi");
307 }
308
309 void NaClBrowserTestPnaclNonSfi::SetUpCommandLine(
310     base::CommandLine* command_line) {
311   NaClBrowserTestBase::SetUpCommandLine(command_line);
312   command_line->AppendSwitch(switches::kEnableNaClNonSfiMode);
313 }
314
315 void NaClBrowserTestNewlibExtension::SetUpCommandLine(
316     CommandLine* command_line) {
317   NaClBrowserTestBase::SetUpCommandLine(command_line);
318   base::FilePath src_root;
319   ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_root));
320
321   // Extension-based tests should specialize the GetDocumentRoot() / Variant()
322   // to point at the isolated the test extension directory.
323   // Otherwise, multiple NaCl extensions tests will end up sharing the
324   // same directory when loading the extension files.
325   base::FilePath document_root;
326   ASSERT_TRUE(GetDocumentRoot(&document_root));
327
328   // Document root is relative to source root, and source root may not be CWD.
329   command_line->AppendSwitchPath(switches::kLoadExtension,
330                                  src_root.Append(document_root));
331 }
332
333 void NaClBrowserTestGLibcExtension::SetUpCommandLine(
334     CommandLine* command_line) {
335   NaClBrowserTestBase::SetUpCommandLine(command_line);
336   base::FilePath src_root;
337   ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_root));
338
339   // Extension-based tests should specialize the GetDocumentRoot() / Variant()
340   // to point at the isolated the test extension directory.
341   // Otherwise, multiple NaCl extensions tests will end up sharing the
342   // same directory when loading the extension files.
343   base::FilePath document_root;
344   ASSERT_TRUE(GetDocumentRoot(&document_root));
345
346   // Document root is relative to source root, and source root may not be CWD.
347   command_line->AppendSwitchPath(switches::kLoadExtension,
348                                  src_root.Append(document_root));
349 }