Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(443)

Side by Side Diff: chrome/test/nacl/nacl_browsertest.cc

Issue 10837207: Add NaCl smoke test to browser_tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "base/command_line.h"
6 #include "base/json/json_reader.h"
7 #include "base/path_service.h"
8 #include "base/timer.h"
9 #include "chrome/browser/ui/browser_tabstrip.h"
10 #include "chrome/common/chrome_paths.h"
11 #include "chrome/common/chrome_switches.h"
12 #include "chrome/test/base/in_process_browser_test.h"
13 #include "chrome/test/base/ui_test_utils.h"
14 #include "content/public/browser/dom_operation_notification_details.h"
15 #include "content/public/browser/notification_observer.h"
16 #include "content/public/browser/notification_registrar.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/plugin_service.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "net/base/net_util.h"
22 #include "webkit/plugins/webplugininfo.h"
23
24 namespace {
25
26 const int kTimeoutMs = 90000;
27
28 // Base class for handling a stream of automation messages produced by a
29 // JavascriptTestObserver.
30 class TestMessageHandler {
31 public:
32 enum MessageResponse {
33 // Reset the timeout and keep running.
34 Continue,
sky 2012/08/10 22:34:15 enums should have app caps -> CONTINUE
Nick Bray 2012/08/10 23:16:28 Done.
35 // Stop runnning.
36 Done
37 };
38
39 TestMessageHandler() : ok_(true) {}
40
41 virtual MessageResponse HandleMessage(const std::string &json) = 0;
42
43 void SetError(const std::string &message) {
sky 2012/08/10 22:34:15 string& message That style every where.
Nick Bray 2012/08/10 23:16:28 Done.
44 ok_ = false;
45 error_message_ = message;
46 }
47
48 bool ok() {
sky 2012/08/10 22:34:15 const
49 return ok_;
50 }
51
52 const std::string& error_message() {
sky 2012/08/10 22:34:15 const
Nick Bray 2012/08/10 23:16:28 Done.
53 return error_message_;
54 }
55
56 private:
57 bool ok_;
58 std::string error_message_;
59 };
60
61 // A helper base class that decodes structured automation messages of the form:
62 // {"type": type_name, ...}
63 class StructuredMessageHandler : public TestMessageHandler {
64 public:
sky 2012/08/10 22:34:15 indent one space.
Nick Bray 2012/08/10 23:16:28 Done.
65
sky 2012/08/10 22:34:15 no newline.
Nick Bray 2012/08/10 23:16:28 Done.
66 MessageResponse HandleMessage(const std::string &json) {
67 scoped_ptr<Value> value;
68 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
69 // Automation messages are stringified before they are sent because the
70 // automation channel cannot handle arbitrary objects. This means we
71 // need to decode the json twice to get the original message.
72 value.reset(reader.ReadToValue(json));
73 if (!value.get())
74 return InternalError("Could parse automation JSON: " + json +
75 " because " + reader.GetErrorMessage());
76
77 std::string temp;
78 if (!value->GetAsString(&temp))
79 return InternalError("Message was not a string: " + json);
80
81 value.reset(reader.ReadToValue(temp));
82 if (!value.get())
83 return InternalError("Could not parse message JSON: " + temp +
84 " because " + reader.GetErrorMessage());
85
86 DictionaryValue *msg;
87 if(!value->GetAsDictionary(&msg))
sky 2012/08/10 22:34:15 space after if (here and 91)
Nick Bray 2012/08/10 23:16:28 Done.
88 return InternalError("Message was not an object: " + temp);
89
90 std::string type;
91 if(!msg->GetString("type", &type))
92 return MissingField("unknown", "type");
93
94 return HandleStructuredMessage(type, msg);
95 }
96
97 virtual MessageResponse HandleStructuredMessage(const std::string &type,
98 DictionaryValue *msg) = 0;
99
100 MessageResponse MissingField(const std::string &type,
101 const std::string &field) WARN_UNUSED_RESULT {
sky 2012/08/10 22:34:15 extra space after ) here and 105
Nick Bray 2012/08/10 23:16:28 Done.
102 return InternalError(type + " message did not have field: " + field);
103 }
104
105 MessageResponse InternalError(const std::string &reason) WARN_UNUSED_RESULT {
106 SetError(reason);
107 return Done;
108 }
109 };
110
111 // A simple structured message handler for tests that load nexes.
112 class LoadTestMessageHandler : public StructuredMessageHandler {
113 public:
114 LoadTestMessageHandler() : test_passed_(false) {}
115
116 void Log(const std::string& type, const std::string& message) {
117 // TODO(ncbray) better logging.
118 LOG(INFO) << type << " " << message;
119 }
120
121 MessageResponse HandleStructuredMessage(const std::string& type,
sky 2012/08/10 22:34:15 virtual and OVERRIDE
122 DictionaryValue *msg) {
sky 2012/08/10 22:34:15 Value&
Nick Bray 2012/08/10 23:16:28 Done.
123 if (type == "Log") {
124 std::string message;
125 if (!msg->GetString("message", &message))
126 return MissingField(type, "message");
127 Log("LOG", message);
128 return Continue;
129 } else if (type == "Shutdown") {
130 std::string message;
131 if (!msg->GetString("message", &message))
132 return MissingField(type, "message");
133 if (!msg->GetBoolean("passed", &test_passed_))
134 return MissingField(type, "passed");
135 Log("SHUTDOWN", message);
136 return Done;
137 } else {
138 return InternalError("Unknown message type: " + type);
139 }
140 }
141
142 bool test_passed() {
sky 2012/08/10 22:34:15 const
Nick Bray 2012/08/10 23:16:28 Done.
143 return test_passed_;
144 }
145
146 private:
147 bool test_passed_;
148 };
sky 2012/08/10 22:34:15 DISALLOW...
Nick Bray 2012/08/10 23:16:28 Done.
149
150 // This class captures a stream of automation messages coming from a Javascript
151 // test and dispatches them to a message handler.
152 // TODO(ncbray) factor out and share with PPAPI tests.
153 class JavascriptTestObserver : public content::NotificationObserver {
154 public:
155 JavascriptTestObserver(
156 content::RenderViewHost* render_view_host,
157 TestMessageHandler *handler,
158 base::TimeDelta timeout)
159 : handler_(handler),
160 running_(false) {
161 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE,
162 content::Source<content::RenderViewHost>(render_view_host));
163 timer_.Start(FROM_HERE, timeout, this, &JavascriptTestObserver::TimeOut);
sky 2012/08/10 22:34:15 We do you need a timer here?
Nick Bray 2012/08/10 23:16:28 I had two reasons: 1) This is adapted from the PP
sky 2012/08/13 21:29:57 Nuke the timer. The test suite handles it for you.
164 }
165
166 bool Run() {
sky 2012/08/10 22:34:15 Description?
Nick Bray 2012/08/10 23:16:28 Done.
167 running_ = true;
168 content::RunMessageLoop();
169 running_ = false;
170 return handler_->ok();
171 }
172
173 void Observe(
sky 2012/08/10 22:34:15 virtual OVERRIDE
Nick Bray 2012/08/10 23:16:28 Done.
174 int type,
175 const content::NotificationSource& source,
176 const content::NotificationDetails& details) {
177 DCHECK(type == content::NOTIFICATION_DOM_OPERATION_RESPONSE);
178 content::Details<content::DomOperationNotificationDetails> dom_op_details(
179 details);
180 // We might receive responses for other script execution, but we only
181 // care about the test finished message.
182 TestMessageHandler::MessageResponse response =
183 handler_->HandleMessage(dom_op_details->json);
184
185 if (response == TestMessageHandler::Done) {
186 EndTest();
187 } else {
188 Continue();
189 }
190 }
191
192 private:
193 void Continue() {
194 timer_.Reset();
195 }
196
197 void TimeOut() {
198 Error("The test timed out.");
199 }
200
201 void Error(const std::string& message) {
202 handler_->SetError(message);
203 EndTest();
204 }
205
206 void EndTest() {
207 if (running_) {
208 timer_.Stop();
209 MessageLoopForUI::current()->Quit();
210 }
211 }
212
213 TestMessageHandler* handler_;
214 bool running_;
215 content::NotificationRegistrar registrar_;
216 base::OneShotTimer<JavascriptTestObserver> timer_;
217
218 DISALLOW_COPY_AND_ASSIGN(JavascriptTestObserver);
219 };
220
221 // NaCl browser tests serve files out of the build directory because nexes and
222 // pexes are artifacts of the build. To keep things tidy, all test data is kept
223 // in a subdirectory. Several variants of a test may be run, for example when
224 // linked against newlib and when linked against glibc. These variants are kept
225 // in different subdirectories. For example, the build directory will look
226 // something like this on Linux:
227 // out/
228 // Release/
229 // nacl_test_data/
230 // newlib/
231 // glibc/
232 bool GetNaClVariantRoot(const FilePath::StringType& variant,
233 FilePath* document_root) {
234 if (!ui_test_utils::GetRelativeBuildDirectory(document_root)) {
sky 2012/08/10 22:34:15 no {}
Nick Bray 2012/08/10 23:16:28 Done.
235 return false;
236 }
237 *document_root = document_root->Append(FILE_PATH_LITERAL("nacl_test_data"));
238 *document_root = document_root->Append(variant);
239 return true;
240 }
241
242 class NaClBrowserTestBase : public InProcessBrowserTest {
243 public:
244 NaClBrowserTestBase() {}
245
246 void SetUpCommandLine(CommandLine* command_line) {
sky 2012/08/10 22:34:15 virtual and OVERRIDE
Nick Bray 2012/08/10 23:16:28 Done.
247 command_line->AppendSwitch(switches::kNoFirstRun);
248 command_line->AppendSwitch(switches::kEnableNaCl);
249 }
250
251 void SetUpInProcessBrowserTestFixture() {
252 // Sanity check.
253 FilePath plugin_lib;
254 ASSERT_TRUE(PathService::Get(chrome::FILE_NACL_PLUGIN, &plugin_lib));
255 ASSERT_TRUE(file_util::PathExists(plugin_lib)) << plugin_lib.value();
256
257 ASSERT_TRUE(StartTestServer()) << "Cannot start test server.";
258 }
259
260 virtual FilePath::StringType variant() = 0;
sky 2012/08/10 22:34:15 virtual methods use CamelCase
Nick Bray 2012/08/10 23:16:28 Done.
261
262 GURL TestURL(const FilePath::StringType& test_file) {
263 FilePath real_path = test_server_->document_root().Append(test_file);
264 EXPECT_TRUE(file_util::PathExists(real_path)) << real_path.value();
265 FilePath url_path = FilePath(FILE_PATH_LITERAL("files"));
266 url_path = url_path.Append(test_file);
267 return test_server_->GetURL(url_path.value());
268 }
269
270 bool RunJavascriptTest(const GURL& url, TestMessageHandler *handler) {
271 JavascriptTestObserver observer(
272 chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
273 handler,
274 base::TimeDelta::FromMilliseconds(kTimeoutMs));
275 ui_test_utils::NavigateToURL(browser(), url);
276 return observer.Run();
277 }
278
279 void RunLoadTest(const FilePath::StringType& test_file) {
280 LoadTestMessageHandler handler;
281 bool ok = RunJavascriptTest(TestURL(test_file), &handler);
282 ASSERT_TRUE(ok) << handler.error_message();
283 ASSERT_TRUE(handler.test_passed()) << "Test failed.";
284 }
285
286 private:
287 bool StartTestServer() {
288 // Launch the web server.
289 FilePath document_root;
290 if (!GetNaClVariantRoot(variant(), &document_root))
291 return false;
292 test_server_.reset(new net::TestServer(net::TestServer::TYPE_HTTP,
293 net::TestServer::kLocalhost,
294 document_root));
295 return test_server_->Start();
296 }
297
298 scoped_ptr<net::TestServer> test_server_;
299 };
300
301 class NaClBrowserTestNewlib : public NaClBrowserTestBase {
302 virtual FilePath::StringType variant() {
303 return FILE_PATH_LITERAL("newlib");
sky 2012/08/10 22:34:15 Isn't there a better way to pass this in? gtest su
Nick Bray 2012/08/10 23:16:28 I'll look into this.
304 }
305 };
306
307 class NaClBrowserTestGLibc : public NaClBrowserTestBase {
308 virtual FilePath::StringType variant() {
309 return FILE_PATH_LITERAL("glibc");
310 }
311 };
312
313 IN_PROC_BROWSER_TEST_F(NaClBrowserTestNewlib, SimpleLoadTest) {
314 RunLoadTest(FILE_PATH_LITERAL("nacl_load_test.html"));
315 }
316
317 IN_PROC_BROWSER_TEST_F(NaClBrowserTestGLibc, SimpleLoadTest) {
318 RunLoadTest(FILE_PATH_LITERAL("nacl_load_test.html"));
319 }
320
321 } // namespace anonymous
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698