Home | History | Annotate | Download | only in tests
      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