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 +}