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

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: Edits 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,
35 // Stop runnning.
36 DONE
37 };
38
39 TestMessageHandler() : ok_(true) {}
sky 2012/08/13 21:29:57 Add a virtual destructor.
Nick Bray (chromium) 2012/08/13 23:16:26 Done.
40
41 virtual MessageResponse HandleMessage(const std::string& json) = 0;
42
43 void SetError(const std::string& message) {
44 ok_ = false;
45 error_message_ = message;
46 }
47
48 bool ok() const {
49 return ok_;
50 }
51
52 const std::string& error_message() const {
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:
65 MessageResponse HandleMessage(const std::string& json) {
sky 2012/08/13 21:29:57 virtual OVERRIDE
Nick Bray (chromium) 2012/08/13 23:16:26 Done.
66 scoped_ptr<Value> value;
67 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
68 // Automation messages are stringified before they are sent because the
69 // automation channel cannot handle arbitrary objects. This means we
70 // need to decode the json twice to get the original message.
71 value.reset(reader.ReadToValue(json));
72 if (!value.get())
73 return InternalError("Could parse automation JSON: " + json +
74 " because " + reader.GetErrorMessage());
75
76 std::string temp;
77 if (!value->GetAsString(&temp))
78 return InternalError("Message was not a string: " + json);
79
80 value.reset(reader.ReadToValue(temp));
81 if (!value.get())
82 return InternalError("Could not parse message JSON: " + temp +
83 " because " + reader.GetErrorMessage());
84
85 DictionaryValue *msg;
sky 2012/08/13 21:29:57 * on the other side, eg DictionaryValue* msg. Sear
Nick Bray (chromium) 2012/08/13 23:16:26 I fixed the "&" issues, but forgot about the "*" i
86 if (!value->GetAsDictionary(&msg))
87 return InternalError("Message was not an object: " + temp);
88
89 std::string type;
90 if (!msg->GetString("type", &type))
91 return MissingField("unknown", "type");
92
93 return HandleStructuredMessage(type, msg);
94 }
95
96 virtual MessageResponse HandleStructuredMessage(const std::string& type,
97 DictionaryValue *msg) = 0;
98
99 MessageResponse MissingField(const std::string& type,
100 const std::string& field) WARN_UNUSED_RESULT {
101 return InternalError(type + " message did not have field: " + field);
102 }
103
104 MessageResponse InternalError(const std::string& reason) WARN_UNUSED_RESULT {
105 SetError(reason);
106 return DONE;
107 }
108 };
sky 2012/08/13 21:29:57 DISALLOW_...
Nick Bray (chromium) 2012/08/13 23:16:26 Abstract class.
109
110 // A simple structured message handler for tests that load nexes.
111 class LoadTestMessageHandler : public StructuredMessageHandler {
112 public:
113 LoadTestMessageHandler() : test_passed_(false) {}
114
115 void Log(const std::string& type, const std::string& message) {
116 // TODO(ncbray) better logging.
117 LOG(INFO) << type << " " << message;
118 }
119
120 virtual MessageResponse HandleStructuredMessage(
121 const std::string& type,
122 DictionaryValue* msg) OVERRIDE {
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() const {
143 return test_passed_;
144 }
145
146 private:
147 bool test_passed_;
148
149 DISALLOW_COPY_AND_ASSIGN(LoadTestMessageHandler);
150 };
151
152 // This class captures a stream of automation messages coming from a Javascript
153 // test and dispatches them to a message handler.
154 // TODO(ncbray) factor out and share with PPAPI tests.
155 class JavascriptTestObserver : public content::NotificationObserver {
156 public:
157 JavascriptTestObserver(
158 content::RenderViewHost* render_view_host,
159 TestMessageHandler *handler,
160 base::TimeDelta timeout)
161 : handler_(handler),
162 running_(false) {
163 registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE,
164 content::Source<content::RenderViewHost>(render_view_host));
165 timer_.Start(FROM_HERE, timeout, this, &JavascriptTestObserver::TimeOut);
166 }
167
168 // Pump the message loop until the message handler indicates the Javascript
169 // test is done running. Return true if the test jig functioned correctly and
170 // nothing timed out.
171 bool Run() {
172 running_ = true;
173 content::RunMessageLoop();
174 running_ = false;
175 return handler_->ok();
176 }
177
178 virtual void Observe(
179 int type,
180 const content::NotificationSource& source,
181 const content::NotificationDetails& details) OVERRIDE {
182 DCHECK(type == content::NOTIFICATION_DOM_OPERATION_RESPONSE);
183 content::Details<content::DomOperationNotificationDetails> dom_op_details(
184 details);
185 // We might receive responses for other script execution, but we only
186 // care about the test finished message.
187 TestMessageHandler::MessageResponse response =
188 handler_->HandleMessage(dom_op_details->json);
189
190 if (response == TestMessageHandler::DONE) {
191 EndTest();
192 } else {
193 Continue();
194 }
195 }
196
197 private:
198 void Continue() {
199 timer_.Reset();
200 }
201
202 void TimeOut() {
203 Error("The test timed out.");
204 }
205
206 void Error(const std::string& message) {
207 handler_->SetError(message);
208 EndTest();
209 }
210
211 void EndTest() {
212 if (running_) {
213 timer_.Stop();
214 MessageLoopForUI::current()->Quit();
215 }
216 }
217
218 TestMessageHandler* handler_;
219 bool running_;
220 content::NotificationRegistrar registrar_;
221 base::OneShotTimer<JavascriptTestObserver> timer_;
222
223 DISALLOW_COPY_AND_ASSIGN(JavascriptTestObserver);
224 };
225
226 // NaCl browser tests serve files out of the build directory because nexes and
227 // pexes are artifacts of the build. To keep things tidy, all test data is kept
228 // in a subdirectory. Several variants of a test may be run, for example when
229 // linked against newlib and when linked against glibc. These variants are kept
230 // in different subdirectories. For example, the build directory will look
231 // something like this on Linux:
232 // out/
233 // Release/
234 // nacl_test_data/
235 // newlib/
236 // glibc/
237 bool GetNaClVariantRoot(const FilePath::StringType& variant,
238 FilePath* document_root) {
239 if (!ui_test_utils::GetRelativeBuildDirectory(document_root))
240 return false;
241 *document_root = document_root->Append(FILE_PATH_LITERAL("nacl_test_data"));
242 *document_root = document_root->Append(variant);
243 return true;
244 }
245
246 class NaClBrowserTestBase : public InProcessBrowserTest {
247 public:
248 NaClBrowserTestBase() {}
249
250 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
251 command_line->AppendSwitch(switches::kNoFirstRun);
252 command_line->AppendSwitch(switches::kEnableNaCl);
253 }
254
255 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
256 // Sanity check.
257 FilePath plugin_lib;
258 ASSERT_TRUE(PathService::Get(chrome::FILE_NACL_PLUGIN, &plugin_lib));
259 ASSERT_TRUE(file_util::PathExists(plugin_lib)) << plugin_lib.value();
260
261 ASSERT_TRUE(StartTestServer()) << "Cannot start test server.";
262 }
263
264 virtual FilePath::StringType Variant() = 0;
265
266 GURL TestURL(const FilePath::StringType& test_file) {
267 FilePath real_path = test_server_->document_root().Append(test_file);
268 EXPECT_TRUE(file_util::PathExists(real_path)) << real_path.value();
269
270 FilePath url_path = FilePath(FILE_PATH_LITERAL("files"));
271 url_path = url_path.Append(test_file);
272 return test_server_->GetURL(url_path.MaybeAsASCII());
273 }
274
275 bool RunJavascriptTest(const GURL& url, TestMessageHandler *handler) {
276 JavascriptTestObserver observer(
277 chrome::GetActiveWebContents(browser())->GetRenderViewHost(),
278 handler,
279 base::TimeDelta::FromMilliseconds(kTimeoutMs));
280 ui_test_utils::NavigateToURL(browser(), url);
281 return observer.Run();
282 }
283
284 void RunLoadTest(const FilePath::StringType& test_file) {
285 LoadTestMessageHandler handler;
286 bool ok = RunJavascriptTest(TestURL(test_file), &handler);
287 ASSERT_TRUE(ok) << handler.error_message();
288 ASSERT_TRUE(handler.test_passed()) << "Test failed.";
289 }
290
291 private:
292 bool StartTestServer() {
293 // Launch the web server.
294 FilePath document_root;
295 if (!GetNaClVariantRoot(Variant(), &document_root))
296 return false;
297 test_server_.reset(new net::TestServer(net::TestServer::TYPE_HTTP,
298 net::TestServer::kLocalhost,
299 document_root));
300 return test_server_->Start();
301 }
302
303 scoped_ptr<net::TestServer> test_server_;
304 };
305
306 class NaClBrowserTestNewlib : public NaClBrowserTestBase {
307 virtual FilePath::StringType Variant() {
308 return FILE_PATH_LITERAL("newlib");
309 }
310 };
311
312 class NaClBrowserTestGLibc : public NaClBrowserTestBase {
313 virtual FilePath::StringType Variant() {
314 return FILE_PATH_LITERAL("glibc");
315 }
316 };
317
318 IN_PROC_BROWSER_TEST_F(NaClBrowserTestNewlib, SimpleLoadTest) {
319 RunLoadTest(FILE_PATH_LITERAL("nacl_load_test.html"));
320 }
321
322 IN_PROC_BROWSER_TEST_F(NaClBrowserTestGLibc, SimpleLoadTest) {
323 RunLoadTest(FILE_PATH_LITERAL("nacl_load_test.html"));
324 }
325
326 } // namespace anonymous
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698