testing/mochitest/chrome-harness.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     8 Components.utils.import("resource://gre/modules/NetUtil.jsm");
    10 /*
    11  * getChromeURI converts a URL to a URI
    12  * 
    13  * url: string of a URL (http://mochi.test/test.html)
    14  * returns: a nsiURI object representing the given URL
    15  *
    16  */
    17 function getChromeURI(url) {
    18   var ios = Components.classes["@mozilla.org/network/io-service;1"].
    19               getService(Components.interfaces.nsIIOService);
    20   return ios.newURI(url, null, null);
    21 }
    23 /*
    24  * Convert a URL (string) into a nsIURI or NSIJARURI
    25  * This is intended for URL's that are on a file system 
    26  * or in packaged up in an extension .jar file
    27  *
    28  * url: a string of a url on the local system(http://localhost/blah.html)
    29  */
    30 function getResolvedURI(url) {
    31   var chromeURI = getChromeURI(url);
    32   var resolvedURI = Components.classes["@mozilla.org/chrome/chrome-registry;1"].
    33                     getService(Components.interfaces.nsIChromeRegistry).
    34                     convertChromeURL(chromeURI);
    36   try {
    37     resolvedURI = resolvedURI.QueryInterface(Components.interfaces.nsIJARURI);
    38   } catch (ex) {} //not a jar file
    40   return resolvedURI;
    41 }
    43 /**
    44  *  getChromeDir is intended to be called after getResolvedURI and convert
    45  *  the input URI into a nsILocalFile (actually the directory containing the
    46  *  file).  This can be used for copying or referencing the file or extra files
    47  *  required by the test.  Usually we need to load a secondary html file or library
    48  *  and this will give us file system access to that.
    49  *
    50  *  resolvedURI: nsIURI (from getResolvedURI) that points to a file:/// url
    51  */
    52 function getChromeDir(resolvedURI) {
    54   var fileHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].
    55                     getService(Components.interfaces.nsIFileProtocolHandler);
    56   var chromeDir = fileHandler.getFileFromURLSpec(resolvedURI.spec);
    57   return chromeDir.parent.QueryInterface(Components.interfaces.nsILocalFile);
    58 }
    60 /*
    61  * given a .jar file, we get all test files located inside the archive
    62  *
    63  * aBasePath: base URL to determine chrome location and search for tests
    64  * aTestPath: passed in testPath value from command line such as: dom/tests/mochitest
    65  * aDir: the test dir to append to the baseURL after getting a directory interface
    66  *
    67  * As a note, this is hardcoded to the .jar structure we use for mochitest.  
    68  * Please don't assume this works for all jar files.
    69  */
    70 function getMochitestJarListing(aBasePath, aTestPath, aDir)
    71 {
    72   var zReader = Components.classes["@mozilla.org/libjar/zip-reader;1"].
    73                   createInstance(Components.interfaces.nsIZipReader);
    74   var fileHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].
    75                     getService(Components.interfaces.nsIFileProtocolHandler);
    77   var fileName = fileHandler.getFileFromURLSpec(getResolvedURI(aBasePath).JARFile.spec);
    78   zReader.open(fileName);
    79   //hardcoded 'content' as that is the root dir in the mochikit.jar file
    80   var idx = aBasePath.indexOf('/content');
    81   var basePath = aBasePath.slice(0, idx);
    83   var base = "content/" + aDir + "/";
    85   if (aTestPath) {
    86     var extraPath = aTestPath;
    87     var pathToCheck = base + aTestPath;
    88     if (zReader.hasEntry(pathToCheck)) {
    89       var pathEntry = zReader.getEntry(pathToCheck);
    90       if (pathEntry.isDirectory) {
    91         base = pathToCheck;
    92       } else {
    93         var singleTestPath = basePath + '/' + base + aTestPath;
    94         var singleObject = {};
    95         singleObject[singleTestPath] = true;
    96         return singleObject;
    97       }
    98     }
    99     else if (zReader.hasEntry(pathToCheck + "/")) {
   100       base = pathToCheck + "/";
   101     }
   102     else {
   103       return null;
   104     }
   105   }
   106   var [links, count] = zList(base, zReader, basePath, true);
   107   return links;
   108 }
   110 /*
   111  * Replicate the server.js list() function with a .jar file
   112  *
   113  * base: string value of base directory we are testing
   114  * zReader: handle to opened nsIZipReader object
   115  * recurse: true|false if we do subdirs
   116  *
   117  * returns:
   118  *  [json object of {dir:{subdir:{file:true, file:true, ...}}}, count of tests]
   119  */
   120 function zList(base, zReader, baseJarName, recurse) {
   121   var dirs = zReader.findEntries(base + "*");
   122   var links = {};
   123   var count = 0;
   124   var fileArray = [];
   126   while(dirs.hasMore()) {
   127     var entryName = dirs.getNext();
   128     if (entryName.substr(-1) == '/' && entryName.split('/').length == (base.split('/').length + 1) ||
   129         (entryName.substr(-1) != '/' && entryName.split('/').length == (base.split('/').length))) { 
   130       fileArray.push(entryName);
   131     }
   132   }
   133   fileArray.sort();
   134   count = fileArray.length;
   135   for (var i=0; i < fileArray.length; i++) {
   136     var myFile = fileArray[i];
   137     if (myFile.substr(-1) === '/' && recurse) {
   138       var childCount = 0;
   139       [links[myFile], childCount] = zList(myFile, zReader, baseJarName, recurse);
   140       count += childCount;
   141     } else {
   142       if (myFile.indexOf("SimpleTest") == -1) {
   143         //we add the '/' so we don't try to run content/content/chrome
   144         links[baseJarName + '/' + myFile] = true;
   145       }
   146     }
   147   }
   148   return [links, count];
   149 }
   151 /**
   152  * basePath: the URL base path to search from such as chrome://mochikit/content/a11y
   153  * testPath: the optional testPath passed into the test such as dom/tests/mochitest
   154  * dir: the test dir to append to the uri after getting a directory interface
   155  * srvScope: loaded javascript to server.js so we have aComponents.classesess to the list() function
   156  *
   157  * return value:
   158  *  single test: [json object, path to test]
   159  *  list of tests: [json object, null] <- directory [heirarchy]
   160  */
   161 function getFileListing(basePath, testPath, dir, srvScope)
   162 {
   163   var uri = getResolvedURI(basePath);
   164   var chromeDir = getChromeDir(uri);
   165   chromeDir.appendRelativePath(dir);
   166   basePath += '/' + dir;
   168   if (testPath == "false" || testPath == false) {
   169     testPath = "";
   170   }
   172   var ioSvc = Components.classes["@mozilla.org/network/io-service;1"].
   173               getService(Components.interfaces.nsIIOService);
   174   var testsDirURI = ioSvc.newFileURI(chromeDir);
   175   var testsDir = ioSvc.newURI(testPath, null, testsDirURI)
   176                   .QueryInterface(Components.interfaces.nsIFileURL).file;
   178   if (testPath != undefined) {
   179     var extraPath = testPath;
   181     var fileNameRegexp = /(browser|test)_.+\.(xul|html|js)$/;
   183     // Invalid testPath...
   184     if (!testsDir.exists())
   185       return null;
   187     if (testsDir.isFile()) {
   188       if (fileNameRegexp.test(testsDir.leafName)) {
   189         var singlePath = basePath + '/' + testPath;
   190         var links = {};
   191         links[singlePath] = true;
   192         return links;
   193       }
   194       // We were passed a file that's not a test...
   195       return null;
   196     }
   198     // otherwise, we were passed a directory of tests
   199     basePath += "/" + testPath;
   200   }
   201   var [links, count] = srvScope.list(basePath, testsDir, true);
   202   return links;
   203 }
   206 //used by tests to determine their directory based off window.location.path
   207 function getRootDirectory(path, chromeURI) {
   208   if (chromeURI === undefined)
   209   {
   210     chromeURI = getChromeURI(path);
   211   }
   212   var myURL = chromeURI.QueryInterface(Components.interfaces.nsIURL);
   213   var mydir = myURL.directory;
   215   if (mydir.match('/$') != '/')
   216   {
   217     mydir += '/';
   218   }
   220   return chromeURI.prePath + mydir;
   221 }
   223 //used by tests to determine their directory based off window.location.path
   224 function getChromePrePath(path, chromeURI) {
   226   if (chromeURI === undefined) {
   227     chromeURI = getChromeURI(path);
   228   }
   230   return chromeURI.prePath;
   231 }
   233 /*
   234  * Given a URI, return nsIJARURI or null
   235  */
   236 function getJar(uri) {
   237   var resolvedURI = getResolvedURI(uri);
   238   var jar = null;
   239   try {
   240     if (resolvedURI.JARFile) {
   241       jar = resolvedURI;
   242     }
   243   } catch (ex) {}
   244   return jar;
   245 }
   247 /*
   248  * input:
   249  *  jar: a nsIJARURI object with the jarfile and jarentry (path in jar file)
   250  *
   251  * output;
   252  *  all files and subdirectories inside jarentry will be extracted to TmpD/mochikit.tmp
   253  *  we will return the location of /TmpD/mochikit.tmp* so you can reference the files locally
   254  */
   255 function extractJarToTmp(jar) {
   256   var tmpdir = Components.classes["@mozilla.org/file/directory_service;1"]
   257                       .getService(Components.interfaces.nsIProperties)
   258                       .get("ProfD", Components.interfaces.nsILocalFile);
   259   tmpdir.append("mochikit.tmp");
   260   // parseInt is used because octal escape sequences cause deprecation warnings
   261   // in strict mode (which is turned on in debug builds)
   262   tmpdir.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, parseInt("0777", 8));
   264   var zReader = Components.classes["@mozilla.org/libjar/zip-reader;1"].
   265                   createInstance(Components.interfaces.nsIZipReader);
   267   var fileHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].
   268                     getService(Components.interfaces.nsIFileProtocolHandler);
   270   var fileName = fileHandler.getFileFromURLSpec(jar.JARFile.spec);
   271   zReader.open(fileName);
   273   //filepath represents the path in the jar file without the filename
   274   var filepath = "";
   275   var parts = jar.JAREntry.split('/');
   276   for (var i =0; i < parts.length - 1; i++) {
   277     if (parts[i] != '') {
   278       filepath += parts[i] + '/';
   279     }
   280   }
   282   /* Create dir structure first, no guarantee about ordering of directories and
   283    * files returned from findEntries.
   284    */
   285   var dirs = zReader.findEntries(filepath + '*/');
   286   while (dirs.hasMore()) {
   287     var targetDir = buildRelativePath(dirs.getNext(), tmpdir, filepath);
   288     // parseInt is used because octal escape sequences cause deprecation warnings
   289     // in strict mode (which is turned on in debug builds)
   290     if (!targetDir.exists()) {
   291       targetDir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, parseInt("0777", 8));
   292     }
   293   }
   295   //now do the files
   296   var files = zReader.findEntries(filepath + "*");
   297   while (files.hasMore()) {
   298     var fname = files.getNext();
   299     if (fname.substr(-1) != '/') {
   300       var targetFile = buildRelativePath(fname, tmpdir, filepath);
   301       zReader.extract(fname, targetFile);
   302     }
   303   }
   304   return tmpdir;
   305 }
   307 /*
   308  * Take a relative path from the current mochitest file
   309  * and returns the absolute path for the given test data file.
   310  */
   311 function getTestFilePath(path) {
   312   if (path[0] == "/") {
   313     throw new Error("getTestFilePath only accepts relative path");
   314   }
   315   // Get the chrome/jar uri for the current mochitest file
   316   // gTestPath being defined by the test harness in browser-chrome tests
   317   // or window is being used for mochitest-browser
   318   var baseURI = typeof(gTestPath) == "string" ? gTestPath : window.location.href;
   319   var parentURI = getResolvedURI(getRootDirectory(baseURI));
   320   var file;
   321   if (parentURI.JARFile) {
   322     // If it's a jar/zip, we have to extract it first
   323     file = extractJarToTmp(parentURI);
   324   } else {
   325     // Otherwise, we can directly cast it to a file URI
   326     var fileHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].
   327                       getService(Components.interfaces.nsIFileProtocolHandler);
   328     file = fileHandler.getFileFromURLSpec(parentURI.spec);
   329   }
   330   // Then walk by the given relative path
   331   path.split("/")
   332       .forEach(function (p) {
   333         if (p == "..") {
   334           file = file.parent;
   335         } else if (p != ".") {
   336           file.append(p);
   337         }
   338       });
   339   return file.path;
   340 }
   342 /*
   343  * Simple utility function to take the directory structure in jarentryname and 
   344  * translate that to a path of a nsILocalFile.
   345  */
   346 function buildRelativePath(jarentryname, destdir, basepath)
   347 {
   348   var baseParts = basepath.split('/');
   349   if (baseParts[baseParts.length-1] == '') {
   350     baseParts.pop();
   351   }
   353   var parts = jarentryname.split('/');
   355   var targetFile = Components.classes["@mozilla.org/file/local;1"]
   356                    .createInstance(Components.interfaces.nsILocalFile);
   357   targetFile.initWithFile(destdir);
   359   for (var i = baseParts.length; i < parts.length; i++) {
   360     targetFile.append(parts[i]);
   361   }
   363   return targetFile;
   364 }
   366 function readConfig(filename) {
   367   filename = filename || "testConfig.js";
   369   var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"].
   370                     getService(Components.interfaces.nsIProperties);
   371   var configFile = fileLocator.get("ProfD", Components.interfaces.nsIFile);
   372   configFile.append(filename);
   374   if (!configFile.exists())
   375     return {};
   377   var fileInStream = Components.classes["@mozilla.org/network/file-input-stream;1"].
   378                      createInstance(Components.interfaces.nsIFileInputStream);
   379   fileInStream.init(configFile, -1, 0, 0);
   381   var str = NetUtil.readInputStreamToString(fileInStream, fileInStream.available());
   382   fileInStream.close();
   383   return JSON.parse(str);
   384 }
   386 function registerTests() {
   387   var testsURI = Components.classes["@mozilla.org/file/directory_service;1"].
   388                  getService(Components.interfaces.nsIProperties).
   389                  get("ProfD", Components.interfaces.nsILocalFile);
   390   testsURI.append("tests.manifest");
   391   var ioSvc = Components.classes["@mozilla.org/network/io-service;1"].
   392               getService(Components.interfaces.nsIIOService);
   393   var manifestFile = ioSvc.newFileURI(testsURI).
   394                      QueryInterface(Components.interfaces.nsIFileURL).file;
   396   Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar).
   397                      autoRegister(manifestFile);
   398 }
   400 function getTestList(params, callback) {
   401   registerTests();
   403   var baseurl = 'chrome://mochitests/content';
   404   if (window.parseQueryString) {
   405     params = parseQueryString(location.search.substring(1), true);
   406   }
   407   if (!params.baseurl) {
   408     params.baseurl = baseurl;
   409   }
   411   var config = readConfig();
   412   for (var p in params) {
   413     if (params[p] == 1) {
   414       config[p] = true;
   415     } else if (params[p] == 0) {
   416       config[p] = false;
   417     } else {
   418       config[p] = params[p];
   419     }
   420   }
   421   params = config;
   422   if (params.manifestFile) {
   423     getTestManifest("http://mochi.test:8888/" + params.manifestFile, params, callback);
   424     return;
   425   }
   427   var links = {};
   428   // load server.js in so we can share template functions
   429   var scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
   430                        getService(Ci.mozIJSSubScriptLoader);
   431   var srvScope = {};
   432   scriptLoader.loadSubScript('chrome://mochikit/content/server.js',
   433                              srvScope);
   435   if (getResolvedURI(baseurl).JARFile) {
   436     links = getMochitestJarListing(baseurl, params.testPath, params.testRoot);
   437   } else {
   438     links = getFileListing(baseurl, params.testPath, params.testRoot, srvScope);
   439   }
   440   callback(links);
   441 }

mercurial