1 <html><head> 2 <meta http-equiv="Pragma" content="no-cache" /> 3 <meta http-equiv="Expires" content="-1" /> 4 <link rel="stylesheet" href="test_page.css"> 5 <script> 6 // Do a deep comparison of two values. Return true if their values are 7 // identical, false otherwise. 8 function deepCompare(left, right) { 9 if (typeof(left) !== typeof(right)) 10 return false; 11 // If their identity is the same or they're basic types with the same value, 12 // they are equal. 13 if (left === right) 14 return true; 15 // If it's a basic type and we got here, we know they're not equal. 16 if (["undefined", "boolean", "number", "string", "function"].indexOf( 17 typeof(left)) > -1) { 18 return false; 19 } 20 // Use right_keys as a set containing all keys from |right| which we haven't 21 // yet compared. 22 var right_keys = {}; 23 for (var key in right) 24 right_keys[key] = true; 25 for (var key in left) { 26 if (key in right_keys) { 27 if (!deepCompare(left[key], right[key])) 28 return false; 29 } else { 30 // |left| had a key that |right| didn't. 31 return false; 32 } 33 delete right_keys[key]; 34 } 35 // If there are keys left in |right_keys|, it means they didn't exist in 36 // |left|, so the objects aren't equal. 37 if (Object.keys(right_keys).length > 0) 38 return false; 39 return true; 40 } 41 42 function AdjustHeight(frameWin) { 43 var div = frameWin.document.getElementsByTagName("div")[0]; 44 var height = frameWin.getComputedStyle(div).height; 45 frameWin.frameElement.style.height = height; 46 } 47 48 // Called when the tests are completed. |result| should be "PASS" if the test(s) 49 // passed, or information about the failure if the test(s) did not pass. 50 function DidExecuteTests(result) { 51 var plugin = document.getElementById("plugin"); 52 if (plugin.parentNode.removePlugin) { 53 plugin.parentNode.removeChild(plugin); 54 plugin = undefined; 55 } 56 if (CheckPostConditions()) 57 sendAutomationMessage(result); 58 59 if (window == top) 60 return; 61 62 // Otherwise, we are in a subframe, so we can use this opportunity to resize 63 // ourselves. 64 AdjustHeight(window); 65 } 66 67 function AppendFrame(testcase, i) { 68 var p = document.createElement("P"); 69 p.setAttribute("class", "frame-container"); 70 71 var title = document.createElement("H2"); 72 title.appendChild(document.createTextNode(testcase)); 73 p.appendChild(title); 74 75 var frame = document.createElement("IFRAME"); 76 var mode = ExtractSearchParameter("mode"); 77 var websocket_host = ExtractSearchParameter("websocket_host"); 78 var websocket_port = ExtractSearchParameter("websocket_port"); 79 var ssl_server_port = ExtractSearchParameter("ssl_server_port"); 80 var src = "?testcase=" + testcase; 81 if (mode == "nacl") 82 src += "&mode=nacl"; 83 if (websocket_host != "") 84 src += "&websocket_host=" + websocket_host; 85 if (websocket_port != "") 86 src += "&websocket_port=" + websocket_port; 87 if (ssl_server_port != "") 88 src += "&ssl_server_port=" + ssl_server_port; 89 frame.setAttribute("src", src); 90 91 frame.setAttribute("onload", "LoadNext(" + (i + 1) + ")"); 92 p.appendChild(frame); 93 94 document.body.appendChild(p); 95 } 96 97 function LoadNext(i) { 98 var links = document.links; 99 if (links.length > i) 100 AppendFrame(links[i].firstChild.nodeValue, i); 101 } 102 103 function RunAll() { 104 // Remove any existing frames. 105 var existing = document.getElementsByClassName("frame-container"); 106 while (existing.length) 107 existing[0].parentNode.removeChild(existing[0]); 108 109 // Add new frames for each test, but do so one frame at a time. 110 LoadNext(0); 111 } 112 113 function ExtractSearchParameter(name) { 114 var nameIndex = location.search.indexOf(name + "="); 115 if (nameIndex != -1) { 116 var value = location.search.substring(nameIndex + name.length + 1); 117 var endIndex = value.indexOf("&"); 118 if (endIndex != -1) 119 value = value.substring(0, endIndex); 120 return value; 121 } 122 return ""; 123 } 124 125 // Parses the message, looking for strings of the form: 126 // TESTING_MESSAGE:<message_type>:<message_contents> 127 // 128 // If the message_data is not a string or does not match the above format, then 129 // undefined is returned. 130 // 131 // Otherwise, returns an array containing 2 items. The 0th element is the 132 // message_type, one of: 133 // - AddPostCondition 134 // - ClearConsole 135 // - DidExecuteTests 136 // - EvalScript 137 // - LogHTML 138 // - RemovePluginWhenFinished 139 // - ReportProgress 140 // The second item is the verbatim message_contents. 141 function ParseTestingMessage(message_data) { 142 if (typeof(message_data) != "string") 143 return undefined; 144 var testing_message_prefix = "TESTING_MESSAGE"; 145 var delim_str = ":"; 146 var delim1 = message_data.indexOf(delim_str); 147 if (message_data.substring(0, delim1) !== testing_message_prefix) 148 return undefined; 149 var delim2 = message_data.indexOf(delim_str, delim1 + 1); 150 if (delim2 == -1) 151 delim2 = message_data.length; 152 var message_type = message_data.substring(delim1 + 1, delim2); 153 var message_contents = message_data.substring(delim2 + 1); 154 return [message_type, message_contents]; 155 } 156 157 function ClearConsole() { 158 window.document.getElementById("console").innerHTML = ""; 159 } 160 161 function LogHTML(html) { 162 window.document.getElementById("console").innerHTML += html; 163 } 164 165 function RemovePluginWhenFinished() { 166 window.document.getElementById("container").removePlugin = true; 167 } 168 169 function sendAutomationMessage(msg) { 170 if (window.domAutomationController) { 171 window.domAutomationController.setAutomationId(0); 172 window.domAutomationController.send(msg); 173 } 174 } 175 176 function LogTestTime(test_time) { 177 console.log(test_time); 178 } 179 180 // If something goes really wrong, the test running inside the plugin may not 181 // terminate. For example, if the plugin does not load, the test will never 182 // send "PASS" to the browser. In this case we should explicitly use the 183 // automation controller to terminate the test. 184 function InternalError(msg) { 185 LogHTML("<p>" + msg); 186 sendAutomationMessage(msg); 187 } 188 189 function EvalScript(script) { 190 try { 191 eval(script); 192 } catch(ex) { 193 } 194 } 195 196 var conditions = []; 197 // Add a "PostCondition". These are bits of script that are run after the plugin 198 // is destroyed. If they evaluate to false or throw an exception, it's 199 // considered a failure. 200 function AddPostCondition(script) { 201 conditions.push(script); 202 } 203 // Update the HTML to show the failure and update cookies so that ui_tests 204 // doesn't count this as a pass. 205 function ConditionFailed(error) { 206 error_string = "Post condition check failed: " + error; 207 InternalError(error_string); 208 } 209 // Iterate through the post conditions defined in |conditions| and check that 210 // they all pass. 211 function CheckPostConditions() { 212 var success = true; 213 for (var i = 0; i < conditions.length; ++i) { 214 var script = conditions[i]; 215 try { 216 if (!eval(script)) { 217 ConditionFailed("\"" + script + "\""); 218 success = false; 219 } 220 } catch (ex) { 221 ConditionFailed("\"" + script + "\"" + " failed with exception: " + 222 "\"" + ex.toString() + "\""); 223 success = false; 224 } 225 } 226 return success; 227 } 228 229 function IsTestingMessage(message_data) { 230 return (ParseTestingMessage(message_data) != undefined); 231 } 232 233 function handleTestingMessage(message_event) { 234 var type_contents_tuple = ParseTestingMessage(message_event.data); 235 if (type_contents_tuple) { 236 var type = type_contents_tuple[0]; 237 var contents = type_contents_tuple[1]; 238 if (type === "AddPostCondition") 239 AddPostCondition(contents); 240 else if (type === "ClearConsole") 241 ClearConsole(); 242 else if (type === "DidExecuteTests") 243 DidExecuteTests(contents); 244 else if (type === "EvalScript") 245 EvalScript(contents); 246 else if (type === "LogHTML") 247 LogHTML(contents); 248 else if (type === "RemovePluginWhenFinished") 249 RemovePluginWhenFinished(); 250 else if (type === "ReportProgress") 251 sendAutomationMessage(contents); 252 else if (type === "LogTestTime") 253 LogTestTime(contents); 254 } 255 } 256 257 function sendProgress() { 258 // We send "..." to signal that we're still working. See 259 // ppapi/tests/testing_instance.h for how this works. 260 sendAutomationMessage("..."); 261 } 262 263 onload = function() { 264 var testcase = ExtractSearchParameter("testcase"); 265 var mode = ExtractSearchParameter("mode"); 266 document.title = 'Test ' + testcase; 267 var obj; 268 if (mode == "nacl_newlib") { 269 obj = document.createElement("EMBED"); 270 obj.setAttribute("src", "ppapi_nacl_tests_newlib.nmf"); 271 obj.setAttribute("type", "application/x-nacl"); 272 obj.setAttribute("mode", mode); 273 } else if (mode == "nacl_glibc") { 274 obj = document.createElement("EMBED"); 275 obj.setAttribute("src", "ppapi_nacl_tests_glibc.nmf"); 276 obj.setAttribute("type", "application/x-nacl"); 277 obj.setAttribute("mode", mode); 278 } else if (mode == "nacl_pnacl") { 279 obj = document.createElement("EMBED"); 280 obj.setAttribute("src", "ppapi_nacl_tests_pnacl.nmf"); 281 obj.setAttribute("type", "application/x-nacl"); 282 obj.setAttribute("mode", mode); 283 } else if (mode == "nacl_pnacl_nonsfi") { 284 obj = document.createElement("EMBED"); 285 obj.setAttribute("src", "ppapi_nacl_tests_pnacl_nonsfi.nmf"); 286 obj.setAttribute("type", "application/x-nacl"); 287 obj.setAttribute("mode", mode); 288 } else { 289 var mimeType = "application/x-ppapi-tests"; 290 if (mimeType in navigator.mimeTypes) { 291 obj = document.createElement("EMBED"); 292 obj.setAttribute("src", "http://a.b.c/test"); 293 obj.setAttribute("type", mimeType); 294 } else { 295 document.getElementById("console").innerHTML = 296 '<span class="fail">FAIL</span>: ' + 297 '<span class="err_msg">Test plug-in is not registered.</span>'; 298 } 299 } 300 if (obj) { 301 obj.setAttribute("width", 80); 302 obj.setAttribute("height", 80); 303 obj.setAttribute("style", 304 "background-color:#AAAAAA;border:1px solid black;"); 305 obj.setAttribute("id", "plugin"); 306 obj.setAttribute("testcase", testcase); 307 obj.setAttribute("protocol", window.location.protocol); 308 var websocket_host = ExtractSearchParameter("websocket_host"); 309 if (websocket_host != "") 310 obj.setAttribute("websocket_host", websocket_host); 311 var websocket_port = ExtractSearchParameter("websocket_port"); 312 if (websocket_port != "") 313 obj.setAttribute("websocket_port", websocket_port); 314 var ssl_server_port = ExtractSearchParameter("ssl_server_port"); 315 if (ssl_server_port != "") 316 obj.setAttribute("ssl_server_port", ssl_server_port); 317 318 var container = document.getElementById("container"); 319 container.addEventListener("message", handleTestingMessage, true); 320 321 // "error" and "crash" events will only fire for NaCl, but adding these 322 // listeners doesn't hurt in the non-NaCl cases. 323 obj.addEventListener("error", function() { 324 InternalError("Plugin did not load. '" + obj.lastError + "'"); 325 }, true); 326 obj.addEventListener("crash", function() { 327 InternalError("Plugin crashed. '" + obj.lastError + "'"); 328 }, true); 329 330 // NaCl sends progress events while loading. When we get one, notify the 331 // domAutomationController so that it knows we're still working. 332 obj.addEventListener("loadstart", sendProgress, true); 333 obj.addEventListener("progress", sendProgress, true); 334 obj.addEventListener("load", sendProgress, true); 335 obj.addEventListener("loadend", sendProgress, true); 336 337 // Register a bad dispatchEvent to make sure it isn't used. See 'EVIL' note 338 // below. 339 var original = obj.dispatchEvent; 340 obj.dispatchEvent = function() { 341 InternalError("Bad dispatchEvent called!"); 342 } 343 container.appendChild(obj); 344 } 345 } 346 347 // EVIL Note: 348 // This part of the script does some nefarious things to make sure that it 349 // doesn't affect the behavior of PostMessage (on which all the tests rely). In 350 // particular, we replace document.createEvent, MessageEvent.initMessageEvent, 351 // and the MessageEvent constructor. Previously, the NaCl integration 352 // implementation made use of these and would fail (http://crbug.com/82604 353 // and http://crbug.com/109775). 354 document.createEvent = function() { 355 InternalError("Bad document.createEvent called!"); 356 } 357 function MessageEvent() { 358 InternalError("Bad MessageEvent constructor called!"); 359 } 360 MessageEvent.prototype.initMessageEvent = function() { 361 InternalError("Bad MessageEvent.initMessageEvent called!"); 362 } 363 364 </script> 365 </head><body> 366 <div> 367 <div id="container"></div> 368 <div id="console"><span class="load_msg">loading...</span></div> 369 </div> 370 </body></html> 371