OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ppapi/tests/test_message_handler.h" | 5 #include "ppapi/tests/test_message_handler.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 #include <map> | 9 #include <map> |
10 #include <sstream> | 10 #include <sstream> |
| 11 #include <vector> |
11 | 12 |
12 #include "ppapi/c/pp_var.h" | 13 #include "ppapi/c/pp_var.h" |
13 #include "ppapi/c/ppb_file_io.h" | 14 #include "ppapi/c/ppb_file_io.h" |
14 #include "ppapi/c/ppb_messaging.h" | 15 #include "ppapi/c/ppb_messaging.h" |
15 #include "ppapi/c/ppp_message_handler.h" | 16 #include "ppapi/c/ppp_message_handler.h" |
16 #include "ppapi/cpp/completion_callback.h" | 17 #include "ppapi/cpp/completion_callback.h" |
17 #include "ppapi/cpp/file_io.h" | 18 #include "ppapi/cpp/file_io.h" |
18 #include "ppapi/cpp/file_ref.h" | 19 #include "ppapi/cpp/file_ref.h" |
19 #include "ppapi/cpp/file_system.h" | 20 #include "ppapi/cpp/file_system.h" |
20 #include "ppapi/cpp/instance.h" | 21 #include "ppapi/cpp/instance.h" |
(...skipping 16 matching lines...) Expand all Loading... |
37 | 38 |
38 REGISTER_TEST_CASE(MessageHandler); | 39 REGISTER_TEST_CASE(MessageHandler); |
39 | 40 |
40 namespace { | 41 namespace { |
41 | 42 |
42 // Created and destroyed on the main thread. All public methods should be called | 43 // Created and destroyed on the main thread. All public methods should be called |
43 // on the main thread. Most data members are only accessed on the main thread. | 44 // on the main thread. Most data members are only accessed on the main thread. |
44 // (Though it handles messages on the background thread). | 45 // (Though it handles messages on the background thread). |
45 class MyMessageHandler : public pp::MessageHandler { | 46 class MyMessageHandler : public pp::MessageHandler { |
46 public: | 47 public: |
47 explicit MyMessageHandler(TestingInstance* instance, | 48 MyMessageHandler(TestingInstance* instance, const pp::MessageLoop& loop) |
48 const pp::MessageLoop& loop) | |
49 : testing_instance_(instance), | 49 : testing_instance_(instance), |
50 message_handler_loop_(loop), | 50 message_handler_loop_(loop), |
51 is_registered_(false), | 51 is_registered_(false), |
52 test_finished_event_(instance->pp_instance()), | 52 test_finished_event_(instance->pp_instance()), |
53 destroy_event_(instance->pp_instance()), | 53 destroy_event_(instance->pp_instance()), |
54 async_message_received_(instance->pp_instance()) { | 54 finished_message_received_(instance->pp_instance()) { |
55 AssertOnMainThread(); | 55 AssertOnMainThread(); |
56 } | 56 } |
57 void Register() { | 57 void Register() { |
58 AssertOnMainThread(); | 58 AssertOnMainThread(); |
59 assert(!is_registered_); | 59 assert(!is_registered_); |
60 int32_t result = | 60 int32_t result = |
61 testing_instance_->RegisterMessageHandler(this, message_handler_loop_); | 61 testing_instance_->RegisterMessageHandler(this, message_handler_loop_); |
62 if (result == PP_OK) { | 62 if (result == PP_OK) { |
63 is_registered_ = true; | 63 is_registered_ = true; |
64 } else { | 64 } else { |
(...skipping 24 matching lines...) Expand all Loading... |
89 assert(!is_registered_); | 89 assert(!is_registered_); |
90 destroy_event_.Wait(); | 90 destroy_event_.Wait(); |
91 destroy_event_.Reset(); | 91 destroy_event_.Reset(); |
92 // Now that we know Destroy() has been called, we know errors_ isn't being | 92 // Now that we know Destroy() has been called, we know errors_ isn't being |
93 // written on the MessageHandler thread anymore. So we can safely read it | 93 // written on the MessageHandler thread anymore. So we can safely read it |
94 // here on the main thread (since destroy_event_ gave us a memory barrier). | 94 // here on the main thread (since destroy_event_ gave us a memory barrier). |
95 std::string temp_errors; | 95 std::string temp_errors; |
96 errors_.swap(temp_errors); | 96 errors_.swap(temp_errors); |
97 return temp_errors; | 97 return temp_errors; |
98 } | 98 } |
99 pp::Var WaitForAsyncMessage() { | 99 void WaitForAsyncMessages(std::vector<pp::Var>* out_vec) { |
100 async_message_received_.Wait(); | 100 finished_message_received_.Wait(); |
101 pp::Var var_to_return = last_async_message_received_; | 101 out_vec->swap(async_messages_received_); |
102 last_async_message_received_ = pp::Var(); | 102 finished_message_received_.Reset(); |
103 async_message_received_.Reset(); | |
104 return var_to_return; | |
105 } | 103 } |
106 private: | 104 private: |
107 static void AssertOnMainThread() { | 105 static void AssertOnMainThread() { |
108 assert(pp::MessageLoop::GetForMainThread() == | 106 assert(pp::MessageLoop::GetForMainThread() == |
109 pp::MessageLoop::GetCurrent()); | 107 pp::MessageLoop::GetCurrent()); |
110 } | 108 } |
111 void AddError(const std::string& error) { | 109 void AddError(const std::string& error) { |
112 if (!error.empty()) { | 110 if (!error.empty()) { |
113 if (!errors_.empty()) | 111 if (!errors_.empty()) |
114 errors_ += "<p>"; | 112 errors_ += "<p>"; |
115 errors_ += error; | 113 errors_ += error; |
116 } | 114 } |
117 } | 115 } |
118 virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) { | 116 virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) { |
119 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) | 117 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) |
120 AddError("HandleMessage was called on the wrong thread!"); | 118 AddError("HandleMessage was called on the wrong thread!"); |
121 if (instance.pp_instance() != testing_instance_->pp_instance()) | 119 if (instance.pp_instance() != testing_instance_->pp_instance()) |
122 AddError("HandleMessage was passed the wrong instance!"); | 120 AddError("HandleMessage was passed the wrong instance!"); |
123 if (var.is_string() && var.AsString() == "FINISHED_TEST") { | 121 if (var.is_string() && var.AsString() == "FINISHED_TEST") { |
124 test_finished_event_.Signal(); | 122 test_finished_event_.Signal(); |
| 123 } else if (var.is_string() && var.AsString() == "FINISHED_WAITING") { |
| 124 finished_message_received_.Signal(); |
125 } else { | 125 } else { |
126 // Any client causing a message to arrive must wait for the message | 126 async_messages_received_.push_back(var); |
127 // before continuing. See WaitForAsyncMessage(). | |
128 assert(last_async_message_received_.is_undefined()); | |
129 last_async_message_received_ = var; | |
130 async_message_received_.Signal(); | |
131 } | 127 } |
132 } | 128 } |
133 | 129 |
134 virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance, | 130 virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance, |
135 const pp::Var& var) { | 131 const pp::Var& var) { |
136 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) | 132 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) |
137 AddError("HandleBlockingMessage was called on the wrong thread!"); | 133 AddError("HandleBlockingMessage was called on the wrong thread!"); |
138 if (instance.pp_instance() != testing_instance_->pp_instance()) | 134 if (instance.pp_instance() != testing_instance_->pp_instance()) |
139 AddError("HandleBlockingMessage was passed the wrong instance!"); | 135 AddError("HandleBlockingMessage was passed the wrong instance!"); |
140 | 136 |
(...skipping 30 matching lines...) Expand all Loading... |
171 // is_registered_ is only read/written on the main thread. | 167 // is_registered_ is only read/written on the main thread. |
172 bool is_registered_; | 168 bool is_registered_; |
173 | 169 |
174 // errors_ is written on the MessageHandler thread. When Destroy() is | 170 // errors_ is written on the MessageHandler thread. When Destroy() is |
175 // called, we stop writing to errors_ and signal destroy_event_. This causes | 171 // called, we stop writing to errors_ and signal destroy_event_. This causes |
176 // a memory barrier, so it's safe to read errors_ after that. | 172 // a memory barrier, so it's safe to read errors_ after that. |
177 std::string errors_; | 173 std::string errors_; |
178 NestedEvent test_finished_event_; | 174 NestedEvent test_finished_event_; |
179 NestedEvent destroy_event_; | 175 NestedEvent destroy_event_; |
180 | 176 |
181 pp::Var last_async_message_received_; | 177 std::vector<pp::Var> async_messages_received_; |
182 NestedEvent async_message_received_; | 178 NestedEvent finished_message_received_; |
183 | 179 |
184 // Undefined & private to disallow copy and assign. | 180 // Undefined & private to disallow copy and assign. |
185 MyMessageHandler(const MyMessageHandler&); | 181 MyMessageHandler(const MyMessageHandler&); |
186 MyMessageHandler& operator=(const MyMessageHandler&); | 182 MyMessageHandler& operator=(const MyMessageHandler&); |
187 }; | 183 }; |
188 | 184 |
189 void FakeHandleMessage(PP_Instance instance, | 185 void FakeHandleMessage(PP_Instance instance, |
190 void* user_data, | 186 void* user_data, |
191 const PP_Var* message_data) {} | 187 const PP_Var* message_data) {} |
192 void FakeHandleBlockingMessage(PP_Instance instance, | 188 void FakeHandleBlockingMessage(PP_Instance instance, |
(...skipping 20 matching lines...) Expand all Loading... |
213 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_2)); | 209 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_2)); |
214 return ppb_messaging_if_ && | 210 return ppb_messaging_if_ && |
215 CheckTestingInterface() && | 211 CheckTestingInterface() && |
216 handler_thread_.Start(); | 212 handler_thread_.Start(); |
217 } | 213 } |
218 | 214 |
219 void TestMessageHandler::RunTests(const std::string& filter) { | 215 void TestMessageHandler::RunTests(const std::string& filter) { |
220 RUN_TEST(RegisterErrorConditions, filter); | 216 RUN_TEST(RegisterErrorConditions, filter); |
221 RUN_TEST(PostMessageAndAwaitResponse, filter); | 217 RUN_TEST(PostMessageAndAwaitResponse, filter); |
222 RUN_TEST(Exceptions, filter); | 218 RUN_TEST(Exceptions, filter); |
| 219 RUN_TEST(BrowserHostedResources, filter); |
223 } | 220 } |
224 | 221 |
225 void TestMessageHandler::HandleMessage(const pp::Var& message_data) { | 222 void TestMessageHandler::HandleMessage(const pp::Var& message_data) { |
226 if (instance()->current_test_name() == "Exceptions") { | 223 if (instance()->current_test_name() == "Exceptions") { |
227 // For TestPostMessageAndAwaitResponse(), all messages should go to the | 224 // For TestPostMessageAndAwaitResponse(), all messages should go to the |
228 // background thread message handler. | 225 // background thread message handler. |
229 assert(false); | 226 assert(false); |
230 } else { | 227 } else { |
231 // Any subtest causing a message to arrive here must wait for it before | 228 // Any subtest causing a message to arrive here must wait for it before |
232 // continuing. See WaitForMessage(). | 229 // continuing. See WaitForMessage(). |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 handler.Unregister(); | 296 handler.Unregister(); |
300 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); | 297 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); |
301 | 298 |
302 PASS(); | 299 PASS(); |
303 } | 300 } |
304 | 301 |
305 std::string TestMessageHandler::TestExceptions() { | 302 std::string TestMessageHandler::TestExceptions() { |
306 MyMessageHandler handler(instance(), | 303 MyMessageHandler handler(instance(), |
307 handler_thread_.message_loop()); | 304 handler_thread_.message_loop()); |
308 { | 305 { |
309 // First, try sending a blocking message when there is no handler | 306 // First try sending a blocking message when there is no handler |
310 // registered. It should throw an exception. | 307 // registered. It should throw an exception. |
311 std::string js_code( | 308 std::string js_code( |
312 "var plugin = document.getElementById('plugin');\n" | 309 "var plugin = document.getElementById('plugin');\n" |
313 "var caught_exception = false;\n" | 310 "var caught_exception = false;\n" |
314 "try {\n" | 311 "try {\n" |
315 " plugin.postMessageAndAwaitResponse('Hello!');\n" | 312 " plugin.postMessageAndAwaitResponse('Hello!');\n" |
316 "} catch (err) {\n" | 313 "} catch (err) {\n" |
317 " caught_exception = true;\n" | 314 " caught_exception = true;\n" |
318 "}\n" | 315 "}\n" |
319 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n"); | 316 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n"); |
320 instance_->EvalScript(js_code); | 317 instance_->EvalScript(js_code); |
321 // Note that we want to wait for the Instance to get the SUCCESS/FAIL | 318 // Note that we want to wait for the Instance to get the SUCCESS/FAIL |
322 // message here. |message_handler| is not yet registered, so the message | 319 // message here. |message_handler| is not yet registered, so the message |
323 // goes to the instance instead. | 320 // goes to the instance instead. |
324 pp::Var msg = WaitForMessage(); | 321 pp::Var msg = WaitForMessage(); |
325 ASSERT_TRUE(msg.is_string()); | 322 ASSERT_TRUE(msg.is_string()); |
326 ASSERT_EQ("SUCCESS", msg.AsString()); | 323 ASSERT_EQ("SUCCESS", msg.AsString()); |
327 } | 324 } |
328 handler.Register(); | 325 handler.Register(); |
329 { | 326 { |
330 // Now that a handler is registered, try requesting and sending a | 327 // Try passing different numbers of arguments; only 1 argument is allowed. |
331 // FileSystem. It should throw an exception. The file system is opened | 328 // Other numbers should throw an exception. |
332 // asynchronously. What *should* happen is that it opens successfully, then | 329 std::string js_code( |
333 // we try to send it via postMessageAndAwaitResponse, which fails with an | 330 "var plugin = document.getElementById('plugin');\n" |
334 // exception. The test could fail either because the filesystem doesn't | 331 "var caught_exception = false;\n" |
335 // open or because postMessageAndAwaitResponse doesn't throw an exception. | 332 "try {\n" |
| 333 " plugin.postMessageAndAwaitResponse();\n" |
| 334 "} catch (err) {\n" |
| 335 " caught_exception = true;\n" |
| 336 "}\n" |
| 337 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" |
| 338 "try {\n" |
| 339 " plugin.postMessageAndAwaitResponse('hello', 5);\n" |
| 340 "} catch (err) {\n" |
| 341 " caught_exception = true;\n" |
| 342 "}\n" |
| 343 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" |
| 344 "plugin.postMessage('FINISHED_WAITING');\n"); |
| 345 instance_->EvalScript(js_code); |
| 346 std::vector<pp::Var> messages; |
| 347 handler.WaitForAsyncMessages(&messages); |
| 348 ASSERT_EQ(2u, messages.size()); |
| 349 ASSERT_EQ("SUCCESS", messages[0].AsString()); |
| 350 ASSERT_EQ("SUCCESS", messages[1].AsString()); |
| 351 } |
| 352 handler.Unregister(); |
| 353 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); |
| 354 |
| 355 PASS(); |
| 356 } |
| 357 |
| 358 std::string TestMessageHandler::TestBrowserHostedResources() { |
| 359 MyMessageHandler handler(instance(), |
| 360 handler_thread_.message_loop()); |
| 361 handler.Register(); |
| 362 { |
| 363 // Try requesting and sending a FileSystem. It should throw an exception. |
| 364 // The file system is opened asynchronously. Once it opens successfully, |
| 365 // then we send it via postMessage and postMessageAndAwaitResponse. We try |
| 366 // both to make sure that the ordering is correct. |
336 std::string js_code( | 367 std::string js_code( |
337 "var plugin = document.getElementById('plugin');\n" | 368 "var plugin = document.getElementById('plugin');\n" |
338 "function gotFileSystem(fs) {\n" | 369 "function gotFileSystem(fs) {\n" |
339 " var caught_exception = false;\n" | 370 " var caught_exception = false;\n" |
340 " try {\n" | 371 " try {\n" |
341 " plugin.postMessageAndAwaitResponse(fs);\n" | 372 " plugin.postMessage(fs);" |
| 373 " plugin.postMessage(fs);" |
| 374 " plugin.postMessage(fs);" |
| 375 " plugin.postMessage(fs);" |
| 376 " var result = plugin.postMessageAndAwaitResponse(fs);\n" |
342 " } catch (err) {\n" | 377 " } catch (err) {\n" |
343 " caught_exception = true;\n" | 378 " caught_exception = true;\n" |
344 " }\n" | 379 " }\n" //TODO(dmichael): Really test that the filesystem is right |
345 " plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" | 380 // ...and FileRef? |
| 381 " plugin.postMessage(result.toString() == fs.toString() ?" |
| 382 " 'SUCCESS' : result.toString());\n" |
| 383 " plugin.postMessage('FINISHED_WAITING');\n" |
346 "}\n" | 384 "}\n" |
347 "function fileSystemError() {\n" | 385 "function fileSystemError() {\n" |
348 " plugin.postMessage('Failed to open filesystem');\n" | 386 " plugin.postMessage('Failed to open filesystem');\n" |
349 "}\n" | 387 "}\n" |
350 "window.webkitRequestFileSystem(\n" | 388 "window.webkitRequestFileSystem(\n" |
351 " window.Temporary, 1024, gotFileSystem, fileSystemError)\n"); | 389 " window.Temporary, 1024, gotFileSystem, fileSystemError)\n"); |
352 instance_->EvalScript(js_code); | 390 instance_->EvalScript(js_code); |
353 pp::Var msg = handler.WaitForAsyncMessage(); | 391 std::vector<pp::Var> messages; |
354 ASSERT_EQ(PP_VARTYPE_STRING, msg.pp_var().type); | 392 handler.WaitForAsyncMessages(&messages); |
355 ASSERT_EQ("SUCCESS", msg.AsString()); | 393 ASSERT_EQ(5u, messages.size()); |
| 394 ASSERT_EQ("SUCCESS", messages.back().AsString()); |
356 } | 395 } |
357 handler.Unregister(); | 396 handler.Unregister(); |
358 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); | 397 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); |
359 | 398 |
360 PASS(); | 399 PASS(); |
361 } | 400 } |
362 | 401 |
| 402 |
363 pp::Var TestMessageHandler::WaitForMessage() { | 403 pp::Var TestMessageHandler::WaitForMessage() { |
364 message_received_.Wait(); | 404 message_received_.Wait(); |
365 pp::Var var_to_return = last_message_; | 405 pp::Var var_to_return = last_message_; |
366 last_message_ = pp::Var(); | 406 last_message_ = pp::Var(); |
367 message_received_.Reset(); | 407 message_received_.Reset(); |
368 return var_to_return; | 408 return var_to_return; |
369 } | 409 } |
370 | 410 |
OLD | NEW |