testing/mochitest/chrome-harness.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/testing/mochitest/chrome-harness.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,441 @@
     1.4 +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +
    1.11 +Components.utils.import("resource://gre/modules/NetUtil.jsm");
    1.12 +
    1.13 +/*
    1.14 + * getChromeURI converts a URL to a URI
    1.15 + * 
    1.16 + * url: string of a URL (http://mochi.test/test.html)
    1.17 + * returns: a nsiURI object representing the given URL
    1.18 + *
    1.19 + */
    1.20 +function getChromeURI(url) {
    1.21 +  var ios = Components.classes["@mozilla.org/network/io-service;1"].
    1.22 +              getService(Components.interfaces.nsIIOService);
    1.23 +  return ios.newURI(url, null, null);
    1.24 +}
    1.25 +
    1.26 +/*
    1.27 + * Convert a URL (string) into a nsIURI or NSIJARURI
    1.28 + * This is intended for URL's that are on a file system 
    1.29 + * or in packaged up in an extension .jar file
    1.30 + *
    1.31 + * url: a string of a url on the local system(http://localhost/blah.html)
    1.32 + */
    1.33 +function getResolvedURI(url) {
    1.34 +  var chromeURI = getChromeURI(url);
    1.35 +  var resolvedURI = Components.classes["@mozilla.org/chrome/chrome-registry;1"].
    1.36 +                    getService(Components.interfaces.nsIChromeRegistry).
    1.37 +                    convertChromeURL(chromeURI);
    1.38 +
    1.39 +  try {
    1.40 +    resolvedURI = resolvedURI.QueryInterface(Components.interfaces.nsIJARURI);
    1.41 +  } catch (ex) {} //not a jar file
    1.42 +
    1.43 +  return resolvedURI;
    1.44 +}
    1.45 +
    1.46 +/**
    1.47 + *  getChromeDir is intended to be called after getResolvedURI and convert
    1.48 + *  the input URI into a nsILocalFile (actually the directory containing the
    1.49 + *  file).  This can be used for copying or referencing the file or extra files
    1.50 + *  required by the test.  Usually we need to load a secondary html file or library
    1.51 + *  and this will give us file system access to that.
    1.52 + *
    1.53 + *  resolvedURI: nsIURI (from getResolvedURI) that points to a file:/// url
    1.54 + */
    1.55 +function getChromeDir(resolvedURI) {
    1.56 +
    1.57 +  var fileHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].
    1.58 +                    getService(Components.interfaces.nsIFileProtocolHandler);
    1.59 +  var chromeDir = fileHandler.getFileFromURLSpec(resolvedURI.spec);
    1.60 +  return chromeDir.parent.QueryInterface(Components.interfaces.nsILocalFile);
    1.61 +}
    1.62 +
    1.63 +/*
    1.64 + * given a .jar file, we get all test files located inside the archive
    1.65 + *
    1.66 + * aBasePath: base URL to determine chrome location and search for tests
    1.67 + * aTestPath: passed in testPath value from command line such as: dom/tests/mochitest
    1.68 + * aDir: the test dir to append to the baseURL after getting a directory interface
    1.69 + *
    1.70 + * As a note, this is hardcoded to the .jar structure we use for mochitest.  
    1.71 + * Please don't assume this works for all jar files.
    1.72 + */
    1.73 +function getMochitestJarListing(aBasePath, aTestPath, aDir)
    1.74 +{
    1.75 +  var zReader = Components.classes["@mozilla.org/libjar/zip-reader;1"].
    1.76 +                  createInstance(Components.interfaces.nsIZipReader);
    1.77 +  var fileHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].
    1.78 +                    getService(Components.interfaces.nsIFileProtocolHandler);
    1.79 +
    1.80 +  var fileName = fileHandler.getFileFromURLSpec(getResolvedURI(aBasePath).JARFile.spec);
    1.81 +  zReader.open(fileName);
    1.82 +  //hardcoded 'content' as that is the root dir in the mochikit.jar file
    1.83 +  var idx = aBasePath.indexOf('/content');
    1.84 +  var basePath = aBasePath.slice(0, idx);
    1.85 +
    1.86 +  var base = "content/" + aDir + "/";
    1.87 +
    1.88 +  if (aTestPath) {
    1.89 +    var extraPath = aTestPath;
    1.90 +    var pathToCheck = base + aTestPath;
    1.91 +    if (zReader.hasEntry(pathToCheck)) {
    1.92 +      var pathEntry = zReader.getEntry(pathToCheck);
    1.93 +      if (pathEntry.isDirectory) {
    1.94 +        base = pathToCheck;
    1.95 +      } else {
    1.96 +        var singleTestPath = basePath + '/' + base + aTestPath;
    1.97 +        var singleObject = {};
    1.98 +        singleObject[singleTestPath] = true;
    1.99 +        return singleObject;
   1.100 +      }
   1.101 +    }
   1.102 +    else if (zReader.hasEntry(pathToCheck + "/")) {
   1.103 +      base = pathToCheck + "/";
   1.104 +    }
   1.105 +    else {
   1.106 +      return null;
   1.107 +    }
   1.108 +  }
   1.109 +  var [links, count] = zList(base, zReader, basePath, true);
   1.110 +  return links;
   1.111 +}
   1.112 +
   1.113 +/*
   1.114 + * Replicate the server.js list() function with a .jar file
   1.115 + *
   1.116 + * base: string value of base directory we are testing
   1.117 + * zReader: handle to opened nsIZipReader object
   1.118 + * recurse: true|false if we do subdirs
   1.119 + *
   1.120 + * returns:
   1.121 + *  [json object of {dir:{subdir:{file:true, file:true, ...}}}, count of tests]
   1.122 + */
   1.123 +function zList(base, zReader, baseJarName, recurse) {
   1.124 +  var dirs = zReader.findEntries(base + "*");
   1.125 +  var links = {};
   1.126 +  var count = 0;
   1.127 +  var fileArray = [];
   1.128 +  
   1.129 +  while(dirs.hasMore()) {
   1.130 +    var entryName = dirs.getNext();
   1.131 +    if (entryName.substr(-1) == '/' && entryName.split('/').length == (base.split('/').length + 1) ||
   1.132 +        (entryName.substr(-1) != '/' && entryName.split('/').length == (base.split('/').length))) { 
   1.133 +      fileArray.push(entryName);
   1.134 +    }
   1.135 +  }
   1.136 +  fileArray.sort();
   1.137 +  count = fileArray.length;
   1.138 +  for (var i=0; i < fileArray.length; i++) {
   1.139 +    var myFile = fileArray[i];
   1.140 +    if (myFile.substr(-1) === '/' && recurse) {
   1.141 +      var childCount = 0;
   1.142 +      [links[myFile], childCount] = zList(myFile, zReader, baseJarName, recurse);
   1.143 +      count += childCount;
   1.144 +    } else {
   1.145 +      if (myFile.indexOf("SimpleTest") == -1) {
   1.146 +        //we add the '/' so we don't try to run content/content/chrome
   1.147 +        links[baseJarName + '/' + myFile] = true;
   1.148 +      }
   1.149 +    }
   1.150 +  }
   1.151 +  return [links, count];
   1.152 +}
   1.153 +
   1.154 +/**
   1.155 + * basePath: the URL base path to search from such as chrome://mochikit/content/a11y
   1.156 + * testPath: the optional testPath passed into the test such as dom/tests/mochitest
   1.157 + * dir: the test dir to append to the uri after getting a directory interface
   1.158 + * srvScope: loaded javascript to server.js so we have aComponents.classesess to the list() function
   1.159 + *
   1.160 + * return value:
   1.161 + *  single test: [json object, path to test]
   1.162 + *  list of tests: [json object, null] <- directory [heirarchy]
   1.163 + */
   1.164 +function getFileListing(basePath, testPath, dir, srvScope)
   1.165 +{
   1.166 +  var uri = getResolvedURI(basePath);
   1.167 +  var chromeDir = getChromeDir(uri);
   1.168 +  chromeDir.appendRelativePath(dir);
   1.169 +  basePath += '/' + dir;
   1.170 +
   1.171 +  if (testPath == "false" || testPath == false) {
   1.172 +    testPath = "";
   1.173 +  }
   1.174 +
   1.175 +  var ioSvc = Components.classes["@mozilla.org/network/io-service;1"].
   1.176 +              getService(Components.interfaces.nsIIOService);
   1.177 +  var testsDirURI = ioSvc.newFileURI(chromeDir);
   1.178 +  var testsDir = ioSvc.newURI(testPath, null, testsDirURI)
   1.179 +                  .QueryInterface(Components.interfaces.nsIFileURL).file;
   1.180 +
   1.181 +  if (testPath != undefined) {
   1.182 +    var extraPath = testPath;
   1.183 +    
   1.184 +    var fileNameRegexp = /(browser|test)_.+\.(xul|html|js)$/;
   1.185 +
   1.186 +    // Invalid testPath...
   1.187 +    if (!testsDir.exists())
   1.188 +      return null;
   1.189 +
   1.190 +    if (testsDir.isFile()) {
   1.191 +      if (fileNameRegexp.test(testsDir.leafName)) {
   1.192 +        var singlePath = basePath + '/' + testPath;
   1.193 +        var links = {};
   1.194 +        links[singlePath] = true;
   1.195 +        return links;
   1.196 +      }
   1.197 +      // We were passed a file that's not a test...
   1.198 +      return null;
   1.199 +    }
   1.200 +
   1.201 +    // otherwise, we were passed a directory of tests
   1.202 +    basePath += "/" + testPath;
   1.203 +  }
   1.204 +  var [links, count] = srvScope.list(basePath, testsDir, true);
   1.205 +  return links;
   1.206 +}
   1.207 +
   1.208 +
   1.209 +//used by tests to determine their directory based off window.location.path
   1.210 +function getRootDirectory(path, chromeURI) {
   1.211 +  if (chromeURI === undefined)
   1.212 +  {
   1.213 +    chromeURI = getChromeURI(path);
   1.214 +  }
   1.215 +  var myURL = chromeURI.QueryInterface(Components.interfaces.nsIURL);
   1.216 +  var mydir = myURL.directory;
   1.217 +
   1.218 +  if (mydir.match('/$') != '/')
   1.219 +  {
   1.220 +    mydir += '/';
   1.221 +  }
   1.222 +
   1.223 +  return chromeURI.prePath + mydir;
   1.224 +}
   1.225 +
   1.226 +//used by tests to determine their directory based off window.location.path
   1.227 +function getChromePrePath(path, chromeURI) {
   1.228 +
   1.229 +  if (chromeURI === undefined) {
   1.230 +    chromeURI = getChromeURI(path);
   1.231 +  }
   1.232 +
   1.233 +  return chromeURI.prePath;
   1.234 +}
   1.235 +
   1.236 +/*
   1.237 + * Given a URI, return nsIJARURI or null
   1.238 + */
   1.239 +function getJar(uri) {
   1.240 +  var resolvedURI = getResolvedURI(uri);
   1.241 +  var jar = null;
   1.242 +  try {
   1.243 +    if (resolvedURI.JARFile) {
   1.244 +      jar = resolvedURI;
   1.245 +    }
   1.246 +  } catch (ex) {}
   1.247 +  return jar;
   1.248 +}
   1.249 +
   1.250 +/*
   1.251 + * input:
   1.252 + *  jar: a nsIJARURI object with the jarfile and jarentry (path in jar file)
   1.253 + *
   1.254 + * output;
   1.255 + *  all files and subdirectories inside jarentry will be extracted to TmpD/mochikit.tmp
   1.256 + *  we will return the location of /TmpD/mochikit.tmp* so you can reference the files locally
   1.257 + */
   1.258 +function extractJarToTmp(jar) {
   1.259 +  var tmpdir = Components.classes["@mozilla.org/file/directory_service;1"]
   1.260 +                      .getService(Components.interfaces.nsIProperties)
   1.261 +                      .get("ProfD", Components.interfaces.nsILocalFile);
   1.262 +  tmpdir.append("mochikit.tmp");
   1.263 +  // parseInt is used because octal escape sequences cause deprecation warnings
   1.264 +  // in strict mode (which is turned on in debug builds)
   1.265 +  tmpdir.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, parseInt("0777", 8));
   1.266 +
   1.267 +  var zReader = Components.classes["@mozilla.org/libjar/zip-reader;1"].
   1.268 +                  createInstance(Components.interfaces.nsIZipReader);
   1.269 +
   1.270 +  var fileHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].
   1.271 +                    getService(Components.interfaces.nsIFileProtocolHandler);
   1.272 +
   1.273 +  var fileName = fileHandler.getFileFromURLSpec(jar.JARFile.spec);
   1.274 +  zReader.open(fileName);
   1.275 +
   1.276 +  //filepath represents the path in the jar file without the filename
   1.277 +  var filepath = "";
   1.278 +  var parts = jar.JAREntry.split('/');
   1.279 +  for (var i =0; i < parts.length - 1; i++) {
   1.280 +    if (parts[i] != '') {
   1.281 +      filepath += parts[i] + '/';
   1.282 +    }
   1.283 +  }
   1.284 +
   1.285 +  /* Create dir structure first, no guarantee about ordering of directories and
   1.286 +   * files returned from findEntries.
   1.287 +   */
   1.288 +  var dirs = zReader.findEntries(filepath + '*/');
   1.289 +  while (dirs.hasMore()) {
   1.290 +    var targetDir = buildRelativePath(dirs.getNext(), tmpdir, filepath);
   1.291 +    // parseInt is used because octal escape sequences cause deprecation warnings
   1.292 +    // in strict mode (which is turned on in debug builds)
   1.293 +    if (!targetDir.exists()) {
   1.294 +      targetDir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, parseInt("0777", 8));
   1.295 +    }
   1.296 +  }
   1.297 +
   1.298 +  //now do the files
   1.299 +  var files = zReader.findEntries(filepath + "*");
   1.300 +  while (files.hasMore()) {
   1.301 +    var fname = files.getNext();
   1.302 +    if (fname.substr(-1) != '/') {
   1.303 +      var targetFile = buildRelativePath(fname, tmpdir, filepath);
   1.304 +      zReader.extract(fname, targetFile);
   1.305 +    }
   1.306 +  }
   1.307 +  return tmpdir;
   1.308 +}
   1.309 +
   1.310 +/*
   1.311 + * Take a relative path from the current mochitest file
   1.312 + * and returns the absolute path for the given test data file.
   1.313 + */
   1.314 +function getTestFilePath(path) {
   1.315 +  if (path[0] == "/") {
   1.316 +    throw new Error("getTestFilePath only accepts relative path");
   1.317 +  }
   1.318 +  // Get the chrome/jar uri for the current mochitest file
   1.319 +  // gTestPath being defined by the test harness in browser-chrome tests
   1.320 +  // or window is being used for mochitest-browser
   1.321 +  var baseURI = typeof(gTestPath) == "string" ? gTestPath : window.location.href;
   1.322 +  var parentURI = getResolvedURI(getRootDirectory(baseURI));
   1.323 +  var file;
   1.324 +  if (parentURI.JARFile) {
   1.325 +    // If it's a jar/zip, we have to extract it first
   1.326 +    file = extractJarToTmp(parentURI);
   1.327 +  } else {
   1.328 +    // Otherwise, we can directly cast it to a file URI
   1.329 +    var fileHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].
   1.330 +                      getService(Components.interfaces.nsIFileProtocolHandler);
   1.331 +    file = fileHandler.getFileFromURLSpec(parentURI.spec);
   1.332 +  }
   1.333 +  // Then walk by the given relative path
   1.334 +  path.split("/")
   1.335 +      .forEach(function (p) {
   1.336 +        if (p == "..") {
   1.337 +          file = file.parent;
   1.338 +        } else if (p != ".") {
   1.339 +          file.append(p);
   1.340 +        }
   1.341 +      });
   1.342 +  return file.path;
   1.343 +}
   1.344 +
   1.345 +/*
   1.346 + * Simple utility function to take the directory structure in jarentryname and 
   1.347 + * translate that to a path of a nsILocalFile.
   1.348 + */
   1.349 +function buildRelativePath(jarentryname, destdir, basepath)
   1.350 +{
   1.351 +  var baseParts = basepath.split('/');
   1.352 +  if (baseParts[baseParts.length-1] == '') {
   1.353 +    baseParts.pop();
   1.354 +  }
   1.355 +
   1.356 +  var parts = jarentryname.split('/');
   1.357 +
   1.358 +  var targetFile = Components.classes["@mozilla.org/file/local;1"]
   1.359 +                   .createInstance(Components.interfaces.nsILocalFile);
   1.360 +  targetFile.initWithFile(destdir);
   1.361 +
   1.362 +  for (var i = baseParts.length; i < parts.length; i++) {
   1.363 +    targetFile.append(parts[i]);
   1.364 +  }
   1.365 +
   1.366 +  return targetFile;
   1.367 +}
   1.368 +
   1.369 +function readConfig(filename) {
   1.370 +  filename = filename || "testConfig.js";
   1.371 +
   1.372 +  var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"].
   1.373 +                    getService(Components.interfaces.nsIProperties);
   1.374 +  var configFile = fileLocator.get("ProfD", Components.interfaces.nsIFile);
   1.375 +  configFile.append(filename);
   1.376 +
   1.377 +  if (!configFile.exists())
   1.378 +    return {};
   1.379 +
   1.380 +  var fileInStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
   1.381 +                     createInstance(Components.interfaces.nsIFileInputStream);
   1.382 +  fileInStream.init(configFile, -1, 0, 0);
   1.383 +
   1.384 +  var str = NetUtil.readInputStreamToString(fileInStream, fileInStream.available());
   1.385 +  fileInStream.close();
   1.386 +  return JSON.parse(str);
   1.387 +}
   1.388 +
   1.389 +function registerTests() {
   1.390 +  var testsURI = Components.classes["@mozilla.org/file/directory_service;1"].
   1.391 +                 getService(Components.interfaces.nsIProperties).
   1.392 +                 get("ProfD", Components.interfaces.nsILocalFile);
   1.393 +  testsURI.append("tests.manifest");
   1.394 +  var ioSvc = Components.classes["@mozilla.org/network/io-service;1"].
   1.395 +              getService(Components.interfaces.nsIIOService);
   1.396 +  var manifestFile = ioSvc.newFileURI(testsURI).
   1.397 +                     QueryInterface(Components.interfaces.nsIFileURL).file;
   1.398 +
   1.399 +  Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar).
   1.400 +                     autoRegister(manifestFile);
   1.401 +}
   1.402 +
   1.403 +function getTestList(params, callback) {
   1.404 +  registerTests();
   1.405 +
   1.406 +  var baseurl = 'chrome://mochitests/content';
   1.407 +  if (window.parseQueryString) {
   1.408 +    params = parseQueryString(location.search.substring(1), true);
   1.409 +  }
   1.410 +  if (!params.baseurl) {
   1.411 +    params.baseurl = baseurl;
   1.412 +  }
   1.413 +
   1.414 +  var config = readConfig();
   1.415 +  for (var p in params) {
   1.416 +    if (params[p] == 1) {
   1.417 +      config[p] = true;
   1.418 +    } else if (params[p] == 0) {
   1.419 +      config[p] = false;
   1.420 +    } else {
   1.421 +      config[p] = params[p];
   1.422 +    }
   1.423 +  }
   1.424 +  params = config;
   1.425 +  if (params.manifestFile) {
   1.426 +    getTestManifest("http://mochi.test:8888/" + params.manifestFile, params, callback);
   1.427 +    return;
   1.428 +  }
   1.429 +
   1.430 +  var links = {};
   1.431 +  // load server.js in so we can share template functions
   1.432 +  var scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
   1.433 +                       getService(Ci.mozIJSSubScriptLoader);
   1.434 +  var srvScope = {};
   1.435 +  scriptLoader.loadSubScript('chrome://mochikit/content/server.js',
   1.436 +                             srvScope);
   1.437 +
   1.438 +  if (getResolvedURI(baseurl).JARFile) {
   1.439 +    links = getMochitestJarListing(baseurl, params.testPath, params.testRoot);
   1.440 +  } else {
   1.441 +    links = getFileListing(baseurl, params.testPath, params.testRoot, srvScope);
   1.442 +  }
   1.443 +  callback(links);
   1.444 +}

mercurial