зеркало из https://github.com/mozilla/gecko-dev.git
198 строки
6.8 KiB
JavaScript
198 строки
6.8 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-*/
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
const {classes: Cc, interfaces: Ci, utils: Cu} = Components
|
|
|
|
Cu.import("resource://gre/modules/FileUtils.jsm");
|
|
|
|
// The xpcshell test harness sets PYTHON so we can read it here.
|
|
let gEnv = Cc["@mozilla.org/process/environment;1"]
|
|
.getService(Ci.nsIEnvironment);
|
|
let gPythonName = gEnv.get("PYTHON");
|
|
|
|
// If we're testing locally, the executable file is in "CurProcD". Otherwise,
|
|
// it is in another location that we have to find.
|
|
function getExecutable(aFilename) {
|
|
let file = FileUtils.getFile("CurProcD", [aFilename]);
|
|
if (!file.exists()) {
|
|
file = FileUtils.getFile("CurWorkD", []);
|
|
while (file.path.contains("xpcshell")) {
|
|
file = file.parent;
|
|
}
|
|
file.append("bin");
|
|
file.append(aFilename);
|
|
}
|
|
return file;
|
|
}
|
|
|
|
let gIsWindows = Cc["@mozilla.org/xre/app-info;1"]
|
|
.getService(Ci.nsIXULRuntime).OS === "WINNT";
|
|
let gDmdTestFile = getExecutable("SmokeDMD" + (gIsWindows ? ".exe" : ""));
|
|
|
|
let gDmdScriptFile = getExecutable("dmd.py");
|
|
|
|
function readFile(aFile) {
|
|
let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
|
|
.createInstance(Ci.nsIFileInputStream);
|
|
let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"]
|
|
.createInstance(Ci.nsIConverterInputStream);
|
|
fstream.init(aFile, -1, 0, 0);
|
|
cstream.init(fstream, "UTF-8", 0, 0);
|
|
|
|
let data = "";
|
|
let str = {};
|
|
let read = 0;
|
|
do {
|
|
// Read as much as we can and put it in str.value.
|
|
read = cstream.readString(0xffffffff, str);
|
|
data += str.value;
|
|
} while (read != 0);
|
|
|
|
cstream.close(); // this closes fstream
|
|
return data.replace(/\r/g, ""); // normalize line endings
|
|
}
|
|
|
|
function runProcess(aExeFile, aArgs) {
|
|
let process = Cc["@mozilla.org/process/util;1"]
|
|
.createInstance(Components.interfaces.nsIProcess);
|
|
process.init(aExeFile);
|
|
process.run(/* blocking = */true, aArgs, aArgs.length);
|
|
return process.exitValue;
|
|
}
|
|
|
|
function test(aPrefix, aArgs) {
|
|
// DMD writes the JSON files to CurWorkD, so we do likewise here with
|
|
// |actualFile| for consistency. It is removed once we've finished.
|
|
let expectedFile = FileUtils.getFile("CurWorkD", [aPrefix + "-expected.txt"]);
|
|
let actualFile = FileUtils.getFile("CurWorkD", [aPrefix + "-actual.txt"]);
|
|
|
|
// Run dmd.py on the JSON file, producing |actualFile|.
|
|
|
|
let args = [
|
|
gDmdScriptFile.path,
|
|
"--filter-stacks-for-testing",
|
|
"-o", actualFile.path
|
|
].concat(aArgs);
|
|
|
|
runProcess(new FileUtils.File(gPythonName), args);
|
|
|
|
// Compare |expectedFile| with |actualFile|. We produce nice diffs with
|
|
// /usr/bin/diff on systems that have it (Mac and Linux). Otherwise (Windows)
|
|
// we do a string compare of the file contents and then print them both if
|
|
// they don't match.
|
|
|
|
let success;
|
|
try {
|
|
let rv = runProcess(new FileUtils.File("/usr/bin/diff"),
|
|
["-u", expectedFile.path, actualFile.path]);
|
|
success = rv == 0;
|
|
|
|
} catch (e) {
|
|
let expectedData = readFile(expectedFile);
|
|
let actualData = readFile(actualFile);
|
|
success = expectedData === actualData;
|
|
if (!success) {
|
|
expectedData = expectedData.split("\n");
|
|
actualData = actualData.split("\n");
|
|
for (let i = 0; i < expectedData.length; i++) {
|
|
print("EXPECTED:" + expectedData[i]);
|
|
}
|
|
for (let i = 0; i < actualData.length; i++) {
|
|
print(" ACTUAL:" + actualData[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
ok(success, aPrefix);
|
|
|
|
actualFile.remove(true);
|
|
}
|
|
|
|
function run_test() {
|
|
let jsonFile, jsonFile2;
|
|
|
|
// These tests do full end-to-end testing of DMD, i.e. both the C++ code that
|
|
// generates the JSON output, and the script that post-processes that output.
|
|
//
|
|
// Run these synchronously, because test() updates the full*.json files
|
|
// in-place (to fix stacks) when it runs dmd.py, and that's not safe to do
|
|
// asynchronously.
|
|
|
|
gEnv.set(gEnv.get("DMD_PRELOAD_VAR"), gEnv.get("DMD_PRELOAD_VALUE"));
|
|
|
|
runProcess(gDmdTestFile, []);
|
|
|
|
function test2(aTestName, aMode) {
|
|
let name = "full-" + aTestName + "-" + aMode;
|
|
jsonFile = FileUtils.getFile("CurWorkD", [name + ".json"]);
|
|
test(name, [jsonFile.path]);
|
|
jsonFile.remove(true);
|
|
}
|
|
|
|
// Please keep this in sync with RunTests() in SmokeDMD.cpp.
|
|
|
|
test2("empty", "live");
|
|
test2("empty", "dark-matter");
|
|
test2("empty", "cumulative");
|
|
|
|
test2("unsampled1", "live");
|
|
test2("unsampled1", "dark-matter");
|
|
|
|
test2("unsampled2", "dark-matter");
|
|
test2("unsampled2", "cumulative");
|
|
|
|
test2("sampled", "live");
|
|
|
|
// These tests only test the post-processing script. They use hand-written
|
|
// JSON files as input. Ideally the JSON files would contain comments
|
|
// explaining how they work, but JSON doesn't allow comments, so I've put
|
|
// explanations here.
|
|
|
|
// This just tests that stack traces of various lengths are truncated
|
|
// appropriately. The number of records in the output is different for each
|
|
// of the tested values.
|
|
jsonFile = FileUtils.getFile("CurWorkD", ["script-max-frames.json"]);
|
|
test("script-max-frames-8",
|
|
["--max-frames=8", jsonFile.path]);
|
|
test("script-max-frames-3",
|
|
["--max-frames=3", "--no-fix-stacks", jsonFile.path]);
|
|
test("script-max-frames-1",
|
|
["--max-frames=1", jsonFile.path]);
|
|
|
|
// This file has three records that are shown in a different order for each
|
|
// of the different sort values. It also tests the handling of gzipped JSON
|
|
// files.
|
|
jsonFile = FileUtils.getFile("CurWorkD", ["script-sort-by.json.gz"]);
|
|
test("script-sort-by-usable",
|
|
["--sort-by=usable", jsonFile.path]);
|
|
test("script-sort-by-req",
|
|
["--sort-by=req", "--no-fix-stacks", jsonFile.path]);
|
|
test("script-sort-by-slop",
|
|
["--sort-by=slop", jsonFile.path]);
|
|
test("script-sort-by-num-blocks",
|
|
["--sort-by=num-blocks", jsonFile.path]);
|
|
|
|
// This file has several real stack traces taken from Firefox execution, each
|
|
// of which tests a different allocator function (or functions).
|
|
jsonFile = FileUtils.getFile("CurWorkD", ["script-ignore-alloc-fns.json"]);
|
|
test("script-ignore-alloc-fns",
|
|
["--ignore-alloc-fns", jsonFile.path]);
|
|
|
|
// This tests "live"-mode diffs.
|
|
jsonFile = FileUtils.getFile("CurWorkD", ["script-diff-live1.json"]);
|
|
jsonFile2 = FileUtils.getFile("CurWorkD", ["script-diff-live2.json"]);
|
|
test("script-diff-live",
|
|
[jsonFile.path, jsonFile2.path]);
|
|
|
|
// This tests "dark-matter"-mode diffs.
|
|
jsonFile = FileUtils.getFile("CurWorkD", ["script-diff-dark-matter1.json"]);
|
|
jsonFile2 = FileUtils.getFile("CurWorkD", ["script-diff-dark-matter2.json"]);
|
|
test("script-diff-dark-matter",
|
|
[jsonFile.path, jsonFile2.path]);
|
|
}
|