toolkit/devtools/server/tests/mochitest/inspector-helpers.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/devtools/server/tests/mochitest/inspector-helpers.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,305 @@
     1.4 +var Cu = Components.utils;
     1.5 +
     1.6 +Cu.import("resource://gre/modules/devtools/Loader.jsm");
     1.7 +Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
     1.8 +Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
     1.9 +
    1.10 +const Services = devtools.require("Services");
    1.11 +const {_documentWalker} = devtools.require("devtools/server/actors/inspector");
    1.12 +
    1.13 +// Always log packets when running tests.
    1.14 +Services.prefs.setBoolPref("devtools.debugger.log", true);
    1.15 +SimpleTest.registerCleanupFunction(function() {
    1.16 +  Services.prefs.clearUserPref("devtools.debugger.log");
    1.17 +});
    1.18 +
    1.19 +
    1.20 +if (!DebuggerServer.initialized) {
    1.21 +  DebuggerServer.init(() => true);
    1.22 +  DebuggerServer.addBrowserActors();
    1.23 +  SimpleTest.registerCleanupFunction(function() {
    1.24 +    DebuggerServer.destroy();
    1.25 +  });
    1.26 +}
    1.27 +
    1.28 +var gAttachCleanups = [];
    1.29 +
    1.30 +SimpleTest.registerCleanupFunction(function() {
    1.31 +  for (let cleanup of gAttachCleanups) {
    1.32 +    cleanup();
    1.33 +  }
    1.34 +});
    1.35 +
    1.36 +/**
    1.37 + * Open a tab, load the url, wait for it to signal its readiness,
    1.38 + * find the tab with the debugger server, and call the callback.
    1.39 + *
    1.40 + * Returns a function which can be called to close the opened ta
    1.41 + * and disconnect its debugger client.
    1.42 + */
    1.43 +function attachURL(url, callback) {
    1.44 +  var win = window.open(url, "_blank");
    1.45 +  var client = null;
    1.46 +
    1.47 +  let cleanup = () => {
    1.48 +    if (client) {
    1.49 +      client.close();
    1.50 +      client = null;
    1.51 +    }
    1.52 +    if (win) {
    1.53 +      win.close();
    1.54 +      win = null;
    1.55 +    }
    1.56 +  };
    1.57 +  gAttachCleanups.push(cleanup);
    1.58 +
    1.59 +  window.addEventListener("message", function loadListener(event) {
    1.60 +    if (event.data === "ready") {
    1.61 +      client = new DebuggerClient(DebuggerServer.connectPipe());
    1.62 +      client.connect((applicationType, traits) => {
    1.63 +        client.listTabs(response => {
    1.64 +          for (let tab of response.tabs) {
    1.65 +            if (tab.url === url) {
    1.66 +              window.removeEventListener("message", loadListener, false);
    1.67 +              client.attachTab(tab.actor, function(aResponse, aTabClient) {
    1.68 +                try {
    1.69 +                  callback(null, client, tab, win.document);
    1.70 +                } catch(ex) {
    1.71 +                  Cu.reportError(ex);
    1.72 +                  dump(ex);
    1.73 +                }
    1.74 +              });
    1.75 +              break;
    1.76 +            }
    1.77 +          }
    1.78 +        });
    1.79 +      });
    1.80 +    }
    1.81 +  }, false);
    1.82 +
    1.83 +  return cleanup;
    1.84 +}
    1.85 +
    1.86 +function promiseOnce(target, event) {
    1.87 +  let deferred = promise.defer();
    1.88 +  target.on(event, (...args) => {
    1.89 +    if (args.length === 1) {
    1.90 +      deferred.resolve(args[0]);
    1.91 +    } else {
    1.92 +      deferred.resolve(args);
    1.93 +    }
    1.94 +  });
    1.95 +  return deferred.promise;
    1.96 +}
    1.97 +
    1.98 +function sortOwnershipChildren(children) {
    1.99 +  return children.sort((a, b) => a.name.localeCompare(b.name));
   1.100 +}
   1.101 +
   1.102 +function serverOwnershipSubtree(walker, node) {
   1.103 +  let actor = walker._refMap.get(node);
   1.104 +  if (!actor) {
   1.105 +    return undefined;
   1.106 +  }
   1.107 +
   1.108 +  let children = [];
   1.109 +  let docwalker = _documentWalker(node, window);
   1.110 +  let child = docwalker.firstChild();
   1.111 +  while (child) {
   1.112 +    let item = serverOwnershipSubtree(walker, child);
   1.113 +    if (item) {
   1.114 +      children.push(item);
   1.115 +    }
   1.116 +    child = docwalker.nextSibling();
   1.117 +  }
   1.118 +  return {
   1.119 +    name: actor.actorID,
   1.120 +    children: sortOwnershipChildren(children)
   1.121 +  }
   1.122 +}
   1.123 +
   1.124 +function serverOwnershipTree(walker) {
   1.125 +  let serverConnection = walker.conn._transport._serverConnection;
   1.126 +  let serverWalker = serverConnection.getActor(walker.actorID);
   1.127 +
   1.128 +  return {
   1.129 +    root: serverOwnershipSubtree(serverWalker, serverWalker.rootDoc ),
   1.130 +    orphaned: [serverOwnershipSubtree(serverWalker, o.rawNode) for (o of serverWalker._orphaned)],
   1.131 +    retained: [serverOwnershipSubtree(serverWalker, o.rawNode) for (o of serverWalker._retainedOrphans)]
   1.132 +  };
   1.133 +}
   1.134 +
   1.135 +function clientOwnershipSubtree(node) {
   1.136 +  return {
   1.137 +    name: node.actorID,
   1.138 +    children: sortOwnershipChildren([clientOwnershipSubtree(child) for (child of node.treeChildren())])
   1.139 +  }
   1.140 +}
   1.141 +
   1.142 +function clientOwnershipTree(walker) {
   1.143 +  return {
   1.144 +    root: clientOwnershipSubtree(walker.rootNode),
   1.145 +    orphaned: [clientOwnershipSubtree(o) for (o of walker._orphaned)],
   1.146 +    retained: [clientOwnershipSubtree(o) for (o of walker._retainedOrphans)]
   1.147 +  }
   1.148 +}
   1.149 +
   1.150 +function ownershipTreeSize(tree) {
   1.151 +  let size = 1;
   1.152 +  for (let child of tree.children) {
   1.153 +    size += ownershipTreeSize(child);
   1.154 +  }
   1.155 +  return size;
   1.156 +}
   1.157 +
   1.158 +function assertOwnershipTrees(walker) {
   1.159 +  let serverTree = serverOwnershipTree(walker);
   1.160 +  let clientTree = clientOwnershipTree(walker);
   1.161 +  is(JSON.stringify(clientTree, null, ' '), JSON.stringify(serverTree, null, ' '), "Server and client ownership trees should match.");
   1.162 +
   1.163 +  return ownershipTreeSize(clientTree.root);
   1.164 +}
   1.165 +
   1.166 +// Verify that an actorID is inaccessible both from the client library and the server.
   1.167 +function checkMissing(client, actorID) {
   1.168 +  let deferred = promise.defer();
   1.169 +  let front = client.getActor(actorID);
   1.170 +  ok(!front, "Front shouldn't be accessible from the client for actorID: " + actorID);
   1.171 +
   1.172 +  let deferred = promise.defer();
   1.173 +  client.request({
   1.174 +    to: actorID,
   1.175 +    type: "request",
   1.176 +  }, response => {
   1.177 +    is(response.error, "noSuchActor", "node list actor should no longer be contactable.");
   1.178 +    deferred.resolve(undefined);
   1.179 +  });
   1.180 +  return deferred.promise;
   1.181 +}
   1.182 +
   1.183 +// Verify that an actorID is accessible both from the client library and the server.
   1.184 +function checkAvailable(client, actorID) {
   1.185 +  let deferred = promise.defer();
   1.186 +  let front = client.getActor(actorID);
   1.187 +  ok(front, "Front should be accessible from the client for actorID: " + actorID);
   1.188 +
   1.189 +  let deferred = promise.defer();
   1.190 +  client.request({
   1.191 +    to: actorID,
   1.192 +    type: "garbageAvailableTest",
   1.193 +  }, response => {
   1.194 +    is(response.error, "unrecognizedPacketType", "node list actor should be contactable.");
   1.195 +    deferred.resolve(undefined);
   1.196 +  });
   1.197 +  return deferred.promise;
   1.198 +}
   1.199 +
   1.200 +function promiseDone(promise) {
   1.201 +  promise.then(null, err => {
   1.202 +    ok(false, "Promise failed: " + err);
   1.203 +    if (err.stack) {
   1.204 +      dump(err.stack);
   1.205 +    }
   1.206 +    SimpleTest.finish();
   1.207 +  });
   1.208 +}
   1.209 +
   1.210 +// Mutation list testing
   1.211 +
   1.212 +function isSrcChange(change) {
   1.213 +  return (change.type === "attributes" && change.attributeName === "src");
   1.214 +}
   1.215 +
   1.216 +function assertAndStrip(mutations, message, test) {
   1.217 +  let size = mutations.length;
   1.218 +  mutations = mutations.filter(test);
   1.219 +  ok((mutations.size != size), message);
   1.220 +  return mutations;
   1.221 +}
   1.222 +
   1.223 +function isSrcChange(change) {
   1.224 +  return change.type === "attributes" && change.attributeName === "src";
   1.225 +}
   1.226 +
   1.227 +function isUnload(change) {
   1.228 +  return change.type === "documentUnload";
   1.229 +}
   1.230 +
   1.231 +function isFrameLoad(change) {
   1.232 +  return change.type === "frameLoad";
   1.233 +}
   1.234 +
   1.235 +function isUnretained(change) {
   1.236 +  return change.type === "unretained";
   1.237 +}
   1.238 +
   1.239 +function isChildList(change) {
   1.240 +  return change.type === "childList";
   1.241 +}
   1.242 +
   1.243 +function isNewRoot(change) {
   1.244 +  return change.type === "newRoot";
   1.245 +}
   1.246 +
   1.247 +// Make sure an iframe's src attribute changed and then
   1.248 +// strip that mutation out of the list.
   1.249 +function assertSrcChange(mutations) {
   1.250 +  return assertAndStrip(mutations, "Should have had an iframe source change.", isSrcChange);
   1.251 +}
   1.252 +
   1.253 +// Make sure there's an unload in the mutation list and strip
   1.254 +// that mutation out of the list
   1.255 +function assertUnload(mutations) {
   1.256 +  return assertAndStrip(mutations, "Should have had a document unload change.", isUnload);
   1.257 +}
   1.258 +
   1.259 +// Make sure there's a frame load in the mutation list and strip
   1.260 +// that mutation out of the list
   1.261 +function assertFrameLoad(mutations) {
   1.262 +  return assertAndStrip(mutations, "Should have had a frame load change.", isFrameLoad);
   1.263 +}
   1.264 +
   1.265 +// Make sure there's a childList change in the mutation list and strip
   1.266 +// that mutation out of the list
   1.267 +function assertChildList(mutations) {
   1.268 +  return assertAndStrip(mutations, "Should have had a frame load change.", isChildList);
   1.269 +}
   1.270 +
   1.271 +// Load mutations aren't predictable, so keep accumulating mutations until
   1.272 +// the one we're looking for shows up.
   1.273 +function waitForMutation(walker, test, mutations=[]) {
   1.274 +  let deferred = promise.defer();
   1.275 +  for (let change of mutations) {
   1.276 +    if (test(change)) {
   1.277 +      deferred.resolve(mutations);
   1.278 +    }
   1.279 +  }
   1.280 +
   1.281 +  walker.once("mutations", newMutations => {
   1.282 +    waitForMutation(walker, test, mutations.concat(newMutations)).then(finalMutations => {
   1.283 +      deferred.resolve(finalMutations);
   1.284 +    })
   1.285 +  });
   1.286 +
   1.287 +  return deferred.promise;
   1.288 +}
   1.289 +
   1.290 +
   1.291 +var _tests = [];
   1.292 +function addTest(test) {
   1.293 +  _tests.push(test);
   1.294 +}
   1.295 +
   1.296 +function runNextTest() {
   1.297 +  if (_tests.length == 0) {
   1.298 +    SimpleTest.finish()
   1.299 +    return;
   1.300 +  }
   1.301 +  var fn = _tests.shift();
   1.302 +  try {
   1.303 +    fn();
   1.304 +  } catch (ex) {
   1.305 +    info("Test function " + (fn.name ? "'" + fn.name + "' " : "") +
   1.306 +         "threw an exception: " + ex);
   1.307 +  }
   1.308 +}

mercurial