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 <string.h> 8 #include <algorithm> 9 #include <map> 10 #include <sstream> 11 12 #include "ppapi/c/pp_var.h" 13 #include "ppapi/c/ppb_file_io.h" 14 #include "ppapi/c/ppb_messaging.h" 15 #include "ppapi/c/ppp_message_handler.h" 16 #include "ppapi/cpp/completion_callback.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/message_handler.h" 22 #include "ppapi/cpp/module_impl.h" 23 #include "ppapi/cpp/network_list.h" 24 #include "ppapi/cpp/network_monitor.h" 25 #include "ppapi/cpp/var.h" 26 #include "ppapi/cpp/var_array.h" 27 #include "ppapi/cpp/var_array_buffer.h" 28 #include "ppapi/cpp/var_dictionary.h" 29 #include "ppapi/tests/pp_thread.h" 30 #include "ppapi/tests/test_utils.h" 31 #include "ppapi/tests/testing_instance.h" 32 33 // Windows defines 'PostMessage', so we have to undef it. 34 #ifdef PostMessage 35 #undef PostMessage 36 #endif 37 38 REGISTER_TEST_CASE(MessageHandler); 39 40 namespace { 41 42 // 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 // (Though it handles messages on the background thread). 45 class EchoingMessageHandler : public pp::MessageHandler { 46 public: 47 explicit EchoingMessageHandler(TestingInstance* instance, 48 const pp::MessageLoop& loop) 49 : testing_instance_(instance), 50 message_handler_loop_(loop), 51 is_registered_(false), 52 test_finished_event_(instance->pp_instance()), 53 destroy_event_(instance->pp_instance()) { 54 AssertOnMainThread(); 55 } 56 void Register() { 57 AssertOnMainThread(); 58 assert(!is_registered_); 59 int32_t result = 60 testing_instance_->RegisterMessageHandler(this, message_handler_loop_); 61 if (result == PP_OK) { 62 is_registered_ = true; 63 } else { 64 std::ostringstream stream; 65 stream << "Failed to register message handler; got error " << result; 66 AddError(stream.str()); 67 test_finished_event_.Signal(); 68 } 69 // Note, at this point, we can't safely read or write errors_ until we wait 70 // on destroy_event_. 71 } 72 void Unregister() { 73 AssertOnMainThread(); 74 assert(is_registered_); 75 testing_instance_->UnregisterMessageHandler(); 76 is_registered_ = false; 77 } 78 void WaitForTestFinishedMessage() { 79 test_finished_event_.Wait(); 80 test_finished_event_.Reset(); 81 } 82 // Wait for Destroy() to be called on the MessageHandler thread. When it's 83 // done, return any errors that occurred during the time the MessageHandler 84 // was getting messages. 85 std::string WaitForDestroy() { 86 AssertOnMainThread(); 87 // If we haven't called Unregister, we'll be waiting forever. 88 assert(!is_registered_); 89 destroy_event_.Wait(); 90 destroy_event_.Reset(); 91 // Now that we know Destroy() has been called, we know errors_ isn't being 92 // written on the MessageHandler thread anymore. So we can safely read it 93 // here on the main thread (since destroy_event_ gave us a memory barrier). 94 std::string temp_errors; 95 errors_.swap(temp_errors); 96 return temp_errors; 97 } 98 private: 99 static void AssertOnMainThread() { 100 assert(pp::MessageLoop::GetForMainThread() == 101 pp::MessageLoop::GetCurrent()); 102 } 103 void AddError(const std::string& error) { 104 if (!error.empty()) { 105 if (!errors_.empty()) 106 errors_ += "<p>"; 107 errors_ += error; 108 } 109 } 110 virtual void HandleMessage(pp::InstanceHandle instance, const pp::Var& var) { 111 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) 112 AddError("HandleMessage was called on the wrong thread!"); 113 if (instance.pp_instance() != testing_instance_->pp_instance()) 114 AddError("HandleMessage was passed the wrong instance!"); 115 if (var.is_string() && var.AsString() == "FINISHED_TEST") 116 test_finished_event_.Signal(); 117 else 118 testing_instance_->PostMessage(var); 119 } 120 121 virtual pp::Var HandleBlockingMessage(pp::InstanceHandle instance, 122 const pp::Var& var) { 123 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) 124 AddError("HandleBlockingMessage was called on the wrong thread!"); 125 if (instance.pp_instance() != testing_instance_->pp_instance()) 126 AddError("HandleBlockingMessage was passed the wrong instance!"); 127 128 // Attempt a blocking operation; make sure it's disallowed. 129 pp::NetworkMonitor monitor(instance); 130 PP_Resource out_param = 0; 131 pp::CompletionCallbackWithOutput<pp::NetworkList> blocking_callback( 132 &out_param); 133 int32_t error = monitor.UpdateNetworkList(blocking_callback); 134 if (error != PP_ERROR_WOULD_BLOCK_THREAD) { 135 AddError("HandleBlockingMessage was allowed to do a blocking call!"); 136 pp::Module::Get()->core()->ReleaseResource(out_param); 137 } 138 139 return var; 140 } 141 142 virtual void WasUnregistered(pp::InstanceHandle instance) { 143 if (pp::MessageLoop::GetCurrent() != message_handler_loop_) 144 AddError("Destroy was called on the wrong thread!"); 145 if (instance.pp_instance() != testing_instance_->pp_instance()) 146 AddError("Destroy was passed the wrong instance!"); 147 destroy_event_.Signal(); 148 } 149 150 // These data members are initialized on the main thread, but don't change for 151 // the life of the object, so are safe to access on the background thread, 152 // because there will be a memory barrier before the the MessageHandler calls 153 // are invoked. 154 TestingInstance* const testing_instance_; 155 const pp::MessageLoop message_handler_loop_; 156 const pp::MessageLoop main_loop_; 157 158 // is_registered_ is only read/written on the main thread. 159 bool is_registered_; 160 161 // errors_ is written on the MessageHandler thread. When Destroy() is 162 // called, we stop writing to errors_ and signal destroy_event_. This causes 163 // a memory barrier, so it's safe to read errors_ after that. 164 std::string errors_; 165 NestedEvent test_finished_event_; 166 NestedEvent destroy_event_; 167 168 // Undefined & private to disallow copy and assign. 169 EchoingMessageHandler(const EchoingMessageHandler&); 170 EchoingMessageHandler& operator=(const EchoingMessageHandler&); 171 }; 172 173 void FakeHandleMessage(PP_Instance instance, 174 void* user_data, 175 const PP_Var* message_data) {} 176 void FakeHandleBlockingMessage(PP_Instance instance, 177 void* user_data, 178 const PP_Var* message_data, 179 PP_Var* result) {} 180 void FakeDestroy(PP_Instance instance, void* user_data) {} 181 182 } // namespace 183 184 TestMessageHandler::TestMessageHandler(TestingInstance* instance) 185 : TestCase(instance), 186 ppb_messaging_if_(NULL), 187 handler_thread_(instance), 188 message_received_(instance->pp_instance()) { 189 } 190 191 TestMessageHandler::~TestMessageHandler() { 192 handler_thread_.Join(); 193 } 194 195 bool TestMessageHandler::Init() { 196 ppb_messaging_if_ = static_cast<const PPB_Messaging_1_2*>( 197 pp::Module::Get()->GetBrowserInterface(PPB_MESSAGING_INTERFACE_1_2)); 198 return ppb_messaging_if_ && 199 CheckTestingInterface() && 200 handler_thread_.Start(); 201 } 202 203 void TestMessageHandler::RunTests(const std::string& filter) { 204 RUN_TEST(RegisterErrorConditions, filter); 205 RUN_TEST(PostMessageAndAwaitResponse, filter); 206 RUN_TEST(Exceptions, filter); 207 } 208 209 void TestMessageHandler::HandleMessage(const pp::Var& message_data) { 210 if (instance()->current_test_name() == "Exceptions") { 211 // For TestPostMessageAndAwaitResponse(), all messages should go to the 212 // background thread message handler. 213 assert(false); 214 } else { 215 if (message_data.is_string()) { 216 last_message_ = message_data.AsString(); 217 } else { 218 last_message_ = "message_data was not a string!"; 219 } 220 message_received_.Signal(); 221 } 222 } 223 224 std::string TestMessageHandler::TestRegisterErrorConditions() { 225 { 226 // Test registering with the main thread as the message loop. 227 PPP_MessageHandler_0_2 fake_ppp_message_handler = { 228 &FakeHandleMessage, &FakeHandleBlockingMessage, &FakeDestroy 229 }; 230 pp::MessageLoop main_loop = pp::MessageLoop::GetForMainThread(); 231 int32_t result = ppb_messaging_if_->RegisterMessageHandler( 232 instance()->pp_instance(), 233 reinterpret_cast<void*>(0xdeadbeef), 234 &fake_ppp_message_handler, 235 main_loop.pp_resource()); 236 ASSERT_EQ(PP_ERROR_WRONG_THREAD, result); 237 } 238 { 239 // Test registering with incomplete PPP_Messaging interface. 240 PPP_MessageHandler_0_2 bad_ppp_ifs[] = { 241 { NULL, &FakeHandleBlockingMessage, &FakeDestroy }, 242 { &FakeHandleMessage, NULL, &FakeDestroy }, 243 { &FakeHandleMessage, &FakeHandleBlockingMessage, NULL }}; 244 for (size_t i = 0; i < sizeof(bad_ppp_ifs)/sizeof(bad_ppp_ifs[0]); ++i) { 245 int32_t result = ppb_messaging_if_->RegisterMessageHandler( 246 instance()->pp_instance(), 247 reinterpret_cast<void*>(0xdeadbeef), 248 &bad_ppp_ifs[i], 249 handler_thread_.message_loop().pp_resource()); 250 ASSERT_EQ(PP_ERROR_BADARGUMENT, result); 251 } 252 } 253 PASS(); 254 } 255 256 std::string TestMessageHandler::TestPostMessageAndAwaitResponse() { 257 EchoingMessageHandler handler(instance(), 258 handler_thread_.message_loop()); 259 // Test doing a sync call before the handler is registered. 260 handler.Register(); 261 std::string js_code("var plugin = document.getElementById('plugin');\n"); 262 js_code += "var result = undefined;\n"; 263 const char* const values_to_test[] = { 264 "5", 265 "undefined", 266 "1.5", 267 "'hello'", 268 "{'key': 'value', 'array_key': [1, 2, 3, 4, 5]}", 269 NULL 270 }; 271 for (size_t i = 0; values_to_test[i]; ++i) { 272 js_code += "result = plugin.postMessageAndAwaitResponse("; 273 js_code += values_to_test[i]; 274 js_code += ");\n"; 275 js_code += "if (!deepCompare(result, "; 276 js_code += values_to_test[i]; 277 js_code += "))\n"; 278 js_code += " InternalError(\" Failed postMessageAndAwaitResponse for: "; 279 js_code += values_to_test[i]; 280 js_code += " result: \" + result);\n"; 281 } 282 instance_->EvalScript(js_code); 283 instance_->EvalScript("plugin.postMessage('FINISHED_TEST');\n"); 284 handler.WaitForTestFinishedMessage(); 285 handler.Unregister(); 286 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); 287 288 PASS(); 289 } 290 291 std::string TestMessageHandler::TestExceptions() { 292 EchoingMessageHandler handler(instance(), 293 handler_thread_.message_loop()); 294 { 295 // First, try sending a blocking message when there is no handler 296 // registered. It should throw an exception. 297 std::string js_code( 298 "var plugin = document.getElementById('plugin');\n" 299 "var caught_exception = false;\n" 300 "try {\n" 301 " plugin.postMessageAndAwaitResponse('Hello!');\n" 302 "} catch (err) {\n" 303 " caught_exception = true;\n" 304 "}\n" 305 "plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n"); 306 instance_->EvalScript(js_code); 307 message_received_.Wait(); 308 ASSERT_EQ("SUCCESS", last_message_); 309 } 310 handler.Register(); 311 { 312 // Now that a handler is registered, try requesting and sending a 313 // FileSystem. It should throw an exception. The file system is opened 314 // asynchronously. What *should* happen is that it opens successfully, then 315 // we try to send it via postMessageAndAwaitResponse, which fails with an 316 // exception. The test could fail either because the filesystem doesn't 317 // open or because postMessageAndAwaitResponse doesn't throw an exception. 318 std::string js_code( 319 "var plugin = document.getElementById('plugin');\n" 320 "function gotFileSystem(fs) {\n" 321 " var caught_exception = false;\n" 322 " try {\n" 323 " plugin.postMessageAndAwaitResponse(fs);\n" 324 " } catch (err) {\n" 325 " caught_exception = true;\n" 326 " }\n" 327 " plugin.postMessage(caught_exception ? 'SUCCESS' : 'FAIL');\n" 328 "}\n" 329 "function fileSystemError() {\n" 330 " plugin.postMessage('Failed to open filesystem');\n" 331 "}\n" 332 "window.webkitRequestFileSystem(\n" 333 " window.Temporary, 1024, gotFileSystem, fileSystemError)\n"); 334 instance_->EvalScript(js_code); 335 message_received_.Wait(); 336 ASSERT_EQ("SUCCESS", last_message_); 337 } 338 handler.Unregister(); 339 ASSERT_SUBTEST_SUCCESS(handler.WaitForDestroy()); 340 341 PASS(); 342 } 343 344