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

Side by Side Diff: ppapi/tests/test_message_handler.cc

Issue 264303002: PPAPI: Implement synchronous postMessage (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: merge Created 6 years, 6 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
« no previous file with comments | « ppapi/tests/test_message_handler.h ('k') | ppapi/thunk/interfaces_ppb_public_dev_channel.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "ppapi/tests/test_message_handler.h"
6
7 #include <stdio.h> // TODO FIXME Remove this!
raymes 2014/06/16 05:33:33 Is this still intentionally here?
dmichael (off chromium) 2014/06/17 18:28:29 Hah, nope, thanks. Sorry for leaving debug junk in
8
9 #include <string.h>
10 #include <algorithm>
11 #include <map>
12 #include <sstream>
13
14 #include "ppapi/c/pp_var.h"
15 #include "ppapi/c/ppb_file_io.h"
16 #include "ppapi/c/ppp_message_handler.h"
17 #include "ppapi/cpp/file_io.h"
18 #include "ppapi/cpp/file_ref.h"
19 #include "ppapi/cpp/file_system.h"
20 #include "ppapi/cpp/instance.h"
21 #include "ppapi/cpp/module_impl.h"
22 #include "ppapi/cpp/var.h"
23 #include "ppapi/cpp/var_array.h"
24 #include "ppapi/cpp/var_array_buffer.h"
25 #include "ppapi/cpp/var_dictionary.h"
26 #include "ppapi/tests/pp_thread.h"
27 #include "ppapi/tests/test_utils.h"
28 #include "ppapi/tests/testing_instance.h"
29
30 // Windows defines 'PostMessage', so we have to undef it.
31 #ifdef PostMessage
32 #undef PostMessage
33 #endif
34
35 REGISTER_TEST_CASE(MessageHandler);
36
37 namespace {
38
39 // Created and destroyed on the main thread. All public methods should be called
40 // on the main thread. Most data members are only accessed on the main thread.
41 // (Though it handles messages on the background thread).
42 class EchoingMessageHandler {
43 public:
44 explicit EchoingMessageHandler(PP_Instance instance,
45 const pp::MessageLoop& loop)
46 : pp_instance_(instance),
47 message_handler_loop_(loop),
48 ppb_messaging_if_(static_cast<const PPB_Messaging_1_1*>(
49 pp::Module::Get()->GetBrowserInterface(
50 PPB_MESSAGING_INTERFACE_1_1))),
51 ppp_message_handler_if_(),
raymes 2014/06/16 05:33:32 is this needed?
dmichael (off chromium) 2014/06/17 18:28:29 Strictly speaking, no, since I set all the fields
52 is_registered_(false),
53 test_finished_event_(instance),
54 destroy_event_(instance) {
55 AssertOnMainThread();
56 ppp_message_handler_if_.HandleMessage = &HandleMessage;
57 ppp_message_handler_if_.HandleBlockingMessage = &HandleBlockingMessage;
58 ppp_message_handler_if_.Destroy = &Destroy;
59 }
60 void Register() {
61 AssertOnMainThread();
62 assert(!is_registered_);
63 int32_t result = ppb_messaging_if_->RegisterMessageHandler(
64 pp_instance_,
65 this,
66 &ppp_message_handler_if_,
67 message_handler_loop_.pp_resource());
68 if (result == PP_OK) {
69 is_registered_ = true;
70 } else {
71 std::ostringstream stream;
72 stream << "Failed to register message handler; got error " << result;
73 AddError(stream.str());
74 test_finished_event_.Signal();
75 }
76 // Note, at this point, we can't safely read or write errors_ until we wait
77 // on destroy_event_.
78 }
79 void Unregister() {
80 AssertOnMainThread();
81 assert(is_registered_);
82 ppb_messaging_if_->UnregisterMessageHandler(pp_instance_);
83 is_registered_ = false;
84 }
85 void WaitForTestFinishedMessage() {
86 test_finished_event_.Wait();
87 test_finished_event_.Reset();
88 }
89 // Wait for Destroy() to be called on the MessageHandler thread. When it's
90 // done, return any errors that occurred during the time the MessageHandler
91 // was getting messages.
92 std::string WaitForDestroy() {
93 AssertOnMainThread();
94 // If we haven't called Unregister, we'll be waiting forever.
95 assert(!is_registered_);
96 destroy_event_.Wait();
97 destroy_event_.Reset();
98 // Now that we know Destroy() has been called, we know errors_ isn't being
99 // written on the MessageHandler thread anymore. So we can safely read it
100 // here on the main thread (since destroy_event_ gave us a memory barrier).
101 std::string temp_errors;
102 errors_.swap(temp_errors);
103 return temp_errors;
104 }
105 private:
106 static void AssertOnMainThread() {
107 assert(pp::MessageLoop::GetForMainThread() ==
108 pp::MessageLoop::GetCurrent());
109 }
110 void AddError(const std::string& error) {
111 if (!error.empty()) {
112 if (!errors_.empty())
113 errors_ += "<p>";
114 errors_ += error;
115 }
116 }
117 static void HandleMessage(PP_Instance instance,
118 void* user_data,
119 struct PP_Var message_data) {
120 pp::Var dbg(message_data);
raymes 2014/06/16 05:33:33 Is this useful?
121 EchoingMessageHandler* thiz =
122 static_cast<EchoingMessageHandler*>(user_data);
123 if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_)
124 thiz->AddError("HandleMessage was called on the wrong thread!");
125 if (instance != thiz->pp_instance_)
126 thiz->AddError("HandleMessage was passed the wrong instance!");
127 pp::Var var(message_data);
128 if (var.is_string() && var.AsString() == "FINISHED_TEST")
129 thiz->test_finished_event_.Signal();
130 else
131 thiz->ppb_messaging_if_->PostMessage(instance, message_data);
132 }
133
134 static PP_Var HandleBlockingMessage(PP_Instance instance,
135 void* user_data,
136 struct PP_Var message_data) {
137 pp::Var dbg(message_data);
raymes 2014/06/16 05:33:32 Same here.
138
139 EchoingMessageHandler* thiz =
140 static_cast<EchoingMessageHandler*>(user_data);
141 if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_)
142 thiz->AddError("HandleBlockingMessage was called on the wrong thread!");
143 if (instance != thiz->pp_instance_)
144 thiz->AddError("HandleBlockingMessage was passed the wrong instance!");
145 // We always need to add a ref when returning a PP_Var, to pass to the
146 // caller.
147 pp::Var take_ref(message_data);
148 take_ref.Detach();
149 return message_data;
raymes 2014/06/16 05:33:32 Why do we need to add a ref? Shouldn't the functio
dmichael (off chromium) 2014/06/17 18:28:29 I tried improving the comment to explain better.
150 }
151
152 static void Destroy(PP_Instance instance, void* user_data) {
153 EchoingMessageHandler* thiz =
154 static_cast<EchoingMessageHandler*>(user_data);
155 if (pp::MessageLoop::GetCurrent() != thiz->message_handler_loop_)
156 thiz->AddError("Destroy was called on the wrong thread!");
157 if (instance != thiz->pp_instance_)
158 thiz->AddError("Destroy was passed the wrong instance!");
159 thiz->destroy_event_.Signal();
160 }
161
162 // These data members are initialized on the main thread, but don't change for
163 // the life of the object, so are safe to access on the background thread,
164 // because there will be a memory barrier before the the MessageHandler calls
165 // are invoked.
166 const PP_Instance pp_instance_;
167 const pp::MessageLoop message_handler_loop_;
168 const pp::MessageLoop main_loop_;
169 const PPB_Messaging_1_1* const ppb_messaging_if_;
170 // Spiritually, this member is const, but we can't initialize it in C++03,
171 // so it has to be non-const to be set in the constructor body.
172 PPP_MessageHandler_0_1 ppp_message_handler_if_;
173
174 // is_registered_ is only read/written on the main thread.
175 bool is_registered_;
176
177 // errors_ is written on the MessageHandler thread. When Destroy() is
178 // called, we stop writing to errors_ and signal destroy_event_. This causes
179 // a memory barrier, so it's safe to read errors_ after that.
180 std::string errors_;
181 NestedEvent test_finished_event_;
182 NestedEvent destroy_event_;
183
184 // Undefined & private to disallow copy and assign.
185 EchoingMessageHandler(const EchoingMessageHandler&);
186 EchoingMessageHandler& operator=(const EchoingMessageHandler&);
187 };
188
189 void FakeHandleMessage(PP_Instance instance,
190 void* user_data,
191 struct PP_Var message_data) {}
raymes 2014/06/16 05:33:32 nit:indentation
192 PP_Var FakeHandleBlockingMessage(PP_Instance instance,
193 void* user_data,
194 struct PP_Var message_data) {
195 return PP_MakeUndefined();
196 }
197 void FakeDestroy(PP_Instance instance, void* user_data) {}
198
199 } // namespace
200
201 TestMessageHandler::TestMessageHandler(TestingInstance* instance)
202 : TestCase(instance),
203 ppb_messaging_if_(NULL),
204 handler_thread_(instance) {
205 }
206
207 TestMessageHandler::~TestMessageHandler() {
208 handler_thread_.Join();
209 }
210
211 bool TestMessageHandler::Init() {
212 ppb_messaging_if_ = static_cast<const PPB_Messaging_1_1*>(
213 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_1));
214 return ppb_messaging_if_ &&
215 CheckTestingInterface() &&
216 handler_thread_.Start();
217 }
218
219 void TestMessageHandler::RunTests(const std::string& filter) {
220 RUN_TEST(RegisterErrorConditions, filter);
221 RUN_TEST(PostMessageAndAwaitResponse, filter);
222 }
223
224 void TestMessageHandler::HandleMessage(const pp::Var& message_data) {
225 // All messages should go to the background thread message handler.
226 assert(false);
227 }
228
229 std::string TestMessageHandler::TestRegisterErrorConditions() {
230 {
231 // Test registering with the main thread as the message loop.
232 PPP_MessageHandler_0_1 fake_ppp_message_handler = {
233 &FakeHandleMessage, &FakeHandleBlockingMessage, &FakeDestroy
234 };
235 pp::MessageLoop main_loop = pp::MessageLoop::GetForMainThread();
236 int32_t result = ppb_messaging_if_->RegisterMessageHandler(
237 instance()->pp_instance(),
238 reinterpret_cast<void*>(0xdeadbeef),
239 &fake_ppp_message_handler,
240 main_loop.pp_resource());
241 ASSERT_EQ(PP_ERROR_WRONG_THREAD, result);
242 }
243 {
244 // Test registering with incomplete PPP_Messaging interface.
245 PPP_MessageHandler_0_1 bad_ppp_ifs[] = {
246 { NULL, &FakeHandleBlockingMessage, &FakeDestroy },
247 { &FakeHandleMessage, NULL, &FakeDestroy },
248 { &FakeHandleMessage, &FakeHandleBlockingMessage, NULL }};
249 for (size_t i = 0; i < sizeof(bad_ppp_ifs)/sizeof(bad_ppp_ifs[0]); ++i) {
250 int32_t result = ppb_messaging_if_->RegisterMessageHandler(
251 instance()->pp_instance(),
252 reinterpret_cast<void*>(0xdeadbeef),
253 &bad_ppp_ifs[i],
254 handler_thread_.message_loop().pp_resource());
255 ASSERT_EQ(PP_ERROR_BADARGUMENT, result);
256 }
257 }
258 PASS();
259 }
260
261 std::string TestMessageHandler::TestPostMessageAndAwaitResponse() {
262 EchoingMessageHandler handler(instance()->pp_instance(),
263 handler_thread_.message_loop());
264 handler.Register();
265 std::string js_code("var plugin = document.getElementById('plugin');\n");
266 js_code += "var result = undefined;\n";
267 const char* const values_to_test[] = {
268 "5",
269 "undefined",
270 "1.5",
271 "'hello'",
272 // TODO(dmichael): There's not an easy way to do a deep comparison in
273 // JavaScript, and no obvious place to put the function to do the
274 // comparison.
raymes 2014/06/16 05:33:33 Could you put it inside test_case.html? Could you
275 // "{'key': 'value', 'array_key': [1, 2, 3, 4, 5]}",
276 NULL
277 };
278 for (size_t i = 0; values_to_test[i]; ++i) {
279 js_code += "result = plugin.postMessageAndAwaitResponse(";
280 js_code += values_to_test[i];
281 js_code += ");\n";
282 js_code += "if (result !== ";
283 js_code += values_to_test[i];
284 js_code += ")\n";
285 js_code += " InternalError(\" Failed postMessageAndAwaitResponse for: ";
286 js_code += values_to_test[i];
287 js_code += " result: \" + result);\n";
288 }
289 // TODO/FIXME: Setting a property uses GetInstanceObject, which sends sync
290 // message, which can get interrupted with message to eval script, etc.
291 // FINISHED_WAITING message can therefore jump ahead.
292 // So checking that postMessageAndAwaitResponse is happening might not be
293 // good enough. Note that HandleFilteredEvent is sync, too.
294 // Maybe add way to check with PepperHungPluginFilter to see if we have any
295 // outbound sync messages. Maybe seperate CL?
296 js_code += "plugin.postMessage('FINISHED_TEST');\n";
297 instance_->EvalScript(js_code);
298 handler.WaitForTestFinishedMessage();
299 handler.Unregister();
300 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy());
301
302 PASS();
303 }
304
OLDNEW
« no previous file with comments | « ppapi/tests/test_message_handler.h ('k') | ppapi/thunk/interfaces_ppb_public_dev_channel.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698