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