Bug 1393788 - Zip all jscov artifacts (.json files) into one file at the finalize stage. r?jmaher, r?gmierz.
MozReview-Commit-ID: DaNLOQuW2lc
--- a/testing/modules/CoverageUtils.jsm
+++ b/testing/modules/CoverageUtils.jsm
@@ -7,31 +7,43 @@
this.EXPORTED_SYMBOLS = [
"CoverageCollector",
]
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
+const OPEN_FLAGS = {
+ RDONLY: parseInt("0x01", 16),
+ WRONLY: parseInt("0x02", 16),
+ CREATE_FILE: parseInt("0x08", 16),
+ APPEND: parseInt("0x10", 16),
+ TRUNCATE: parseInt("0x20", 16),
+ EXCL: parseInt("0x80", 16)
+};
+
/* globals Debugger */
const {addDebuggerToGlobal} = Cu.import("resource://gre/modules/jsdebugger.jsm",
{});
addDebuggerToGlobal(Cu.getGlobalForObject(this));
/**
* Records coverage for each test by way of the js debugger.
*/
this.CoverageCollector = function(prefix) {
this._prefix = prefix;
this._dbg = new Debugger();
this._dbg.collectCoverageInfo = true;
this._dbg.addAllGlobalsAsDebuggees();
this._scripts = this._dbg.findScripts();
+ // Record the filename all jscov artifacts
+ this._jscovFiles = [];
+
this._dbg.onNewScript = (script) => {
this._scripts.push(script);
};
// Source -> coverage data;
this._allCoverage = {};
this._encoder = new TextEncoder();
@@ -210,20 +222,70 @@ CoverageCollector.prototype.recordTestCo
for (let line of uncoveredLines[scriptName]) {
rec.uncovered.push(line);
}
result.push(rec);
}
let arr = this._encoder.encode(JSON.stringify(result, null, 2));
- let path = this._prefix + "/jscov_" + Date.now() + ".json";
+ let json_file = "jscov_" + Date.now() + ".json";
+ this._jscovFiles.push(json_file);
+ let path = this._prefix + "/" + json_file;
dump("Writing coverage to: " + path + "\n");
return OS.File.writeAtomic(path, arr, {tmpPath: path + ".tmp"});
}
/**
+ * Compress all jsdcov artifacts into one zip file.
+ */
+CoverageCollector.prototype._compress_jscov_artifacts = function() {
+ // Setup
+ var FileUtils = Cu.import("resource://gre/modules/FileUtils.jsm").FileUtils;
+ let ccov_scope = {};
+ const {OS} = Cu.import("resource://gre/modules/osfile.jsm", ccov_scope);
+ let openFlags = OPEN_FLAGS.WRONLY | OPEN_FLAGS.CREATE_FILE | OPEN_FLAGS.TRUNCATE;
+
+ // Zip file information
+ var zip_filename = "jscov_artifacts_" + Date.now() + ".zip";
+ var zip_filepath = this._prefix + "/" + zip_filename;
+ dump("Creating zip file: " + zip_filepath + " for storing JSCov artifacts. \n");
+ var zipFile = new FileUtils.File(zip_filepath);
+
+ // Using Mozilla's nsIZipWriter class
+ var zipWriter = Cc["@mozilla.org/zipwriter;1"]
+ .createInstance(Components.interfaces.nsIZipWriter);
+ zipWriter.open(zipFile, openFlags);
+
+ // Iterate through all jscov artifacts
+ dump("Iterate through all JSCov artifacts. \n");
+ var success_zip = false;
+ for (var i = 0; i < this._jscovFiles.length; i++){
+ var jscov_filepath = this._prefix + "/" + this._jscovFiles[i];
+ var jscov_file = new FileUtils.File(jscov_filepath);
+
+ if (jscov_file.exists()){
+ dump("Adding JSCov artifact to the zip file: " + jscov_filepath + "\n");
+ zipWriter.addEntryFile(this._jscovFiles[i],
+ Ci.nsIZipWriter.COMPRESSION_DEFAULT, jscov_file, false);
+
+ // Remove this jsdcov artifact
+ OS.File.remove(jscov_filepath);
+ success_zip = true;
+ } else {
+ dump ("Warning: Cannot find JSCov artifacts: " + jscov_filepath + "\n");
+ }
+ }
+ zipWriter.close();
+
+ if (!success_zip){
+ OS.File.remove(zip_filepath);
+ }
+}
+
+/**
* Tear down the debugger after all tests are complete.
*/
CoverageCollector.prototype.finalize = function() {
this._dbg.removeAllDebuggees();
this._dbg.enabled = false;
+ this._compress_jscov_artifacts();
}
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -1036,16 +1036,56 @@ class XPCShellTests(object):
def verifyDirPath(self, dirname):
"""
Simple wrapper to get the absolute path for a given directory name.
On a remote system, we need to overload this to work on the remote filesystem.
"""
return os.path.abspath(dirname)
+ def launchProcess(self, cmd, stdout, stderr, env, cwd, timeout=None):
+ """
+ Simple wrapper to launch a process.
+ On a remote system, this is more complex and we need to overload this function.
+ """
+ # timeout is needed by remote xpcshell to extend the
+ # devicemanager.shell() timeout. It is not used in this function.
+ if HAVE_PSUTIL:
+ popen_func = psutil.Popen
+ else:
+ popen_func = Popen
+ proc = popen_func(cmd, stdout=stdout, stderr=stderr,
+ env=env, cwd=cwd)
+ return proc
+
+ def compressJSCovArtifacts(self, pStdout, pStderr):
+ """
+ Compress all JSCov artifacts (.json) generated from the XPCShell tests.
+ """
+ if self.jscovdir:
+ self.log.info("INFO | Begin to compress JSCov artifacts. ")
+ # Setup the command for compression
+ timeStamp = str(int(time.time() * 1000))
+ zipFilename = "jscov_artifacts_" + timeStamp + ".zip"
+ zipFile = os.path.join(self.jscovdir, zipFilename)
+ command = ["zip", "-r", zipFile, ".", "-i", "jscov*.json"]
+
+ # Execute command and wait for it to complete
+ proc = self.launchProcess(command, stdout=pStdout, stderr=pStderr,
+ env=self.env, cwd=self.jscovdir)
+ proc.communicate()
+
+ # Delete compressed JSCov artifacts.
+ for filename in os.listdir(self.jscovdir):
+ if filename.startswith("jscov") and filename.endswith(".json"):
+ os.remove( os.path.join(self.jscovdir, filename) )
+
+ self.log.info("INFO | Completed JSCov artifacts compression. ")
+ self.log.info("INFO | Here's the zip file: " + zipFile)
+
def trySetupNode(self):
"""
Run node for HTTP/2 tests, if available, and updates mozinfo as appropriate.
"""
if os.getenv('MOZ_ASSUME_NODE_RUNNING', None):
self.log.info('Assuming required node servers are already running')
if not os.getenv('MOZHTTP2_PORT', None):
self.log.warning('MOZHTTP2_PORT environment variable not set. '
@@ -1378,16 +1418,18 @@ class XPCShellTests(object):
usingTSan=usingTSan, mobileArgs=mobileArgs, **kwargs)
if 'run-sequentially' in test_object or self.sequential:
sequential_tests.append(test)
else:
tests_queue.append(test)
status = self.runTestList(tests_queue, sequential_tests, testClass,
mobileArgs, **kwargs)
+ if self.jscovdir:
+ self.compressJSCovArtifacts(pStdout, pStderr)
else:
#
# Test verification: Run each test many times, in various configurations,
# in hopes of finding intermittent failures.
#
def step1():
# Run tests sequentially. Parallel mode would also work, except that