jones-test/lib/Driver.js (322 lines of code) (raw):

/* Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ "use strict"; var unified_debug = require("unified_debug"), udebug = unified_debug.getLogger("Driver.js"), CommandLine = require("./CommandLine"), Listener = require("./Listener"), LintTest = require("./LintTest"), Result = require("./Result"), Suite = require("./Suite"), path = require("path"), fs = require("fs"); /** Driver */ function Driver(baseDirectory) { this.baseDirectory = baseDirectory; // See default value, below this.flagHandler = new CommandLine.FlagHandler(); this.result = new Result(this); this.result.listener = new Listener.Listener(); this.suites = []; this.fileToRun = ""; this.testInFile = null; this.suitesToRun = null; this.skipSmokeTest = false; this.skipClearSmokeTest = false; this.abortAndExit = false; // --help option this.timeoutMillis = 0; // no timeout this.numberOfRunningSuites = 0; this.exitStatus = 0; if(! baseDirectory) { this.baseDirectory = path.dirname(module.parent.parent.filename); } this.setCommandLineFlags(); } Driver.prototype.resetSuites = function() { this.suites = []; }; Driver.prototype.addCommandLineOption = function(shortForm, longForm, helpText, callback) { this.flagHandler.addOption(new CommandLine.Option(shortForm, longForm, helpText, callback)); }; Driver.prototype.processCommandLineOptions = function() { if(! this.flagHandler.done) { this.flagHandler.processArguments(); } }; Driver.prototype.addLintTestsForDirectory = function(directory) { var suite, tests, i; directory = path.resolve(this.baseDirectory, directory); for(i = 1 ; i < arguments.length ; i++) { directory = path.resolve(directory, arguments[i]); } suite = new Suite(this, "lint"); /* Add the smoke test */ suite.addTest(directory, new LintTest.LintSmokeTest()); /* Add the individual file lint tests */ tests = LintTest.forDirectory(directory); for(i = 0 ; i < tests.length ; i++) { suite.addTest(directory, tests[i]); } this.suites.push(suite); }; Driver.prototype.ignoreLint = function(a, b, c, d) { LintTest.ignore(a, b, c, d); }; Driver.prototype.predefineLint = function(keywords) { LintTest.predefine(keywords); }; Driver.prototype.addSuiteFromFile = function(suitename, filename) { this.suites.push(new Suite(this, suitename, filename)); }; Driver.prototype.addSuitesFromDirectory = function(directory) { var files, f, i, st, suite, nsuites, dir; nsuites = 0; directory = path.resolve(this.baseDirectory, directory); udebug.log_detail("addSuitesFromDirectory:", directory); /* Read the test directory, building list of suites */ files = fs.readdirSync(directory); for(i = 0; i < files.length ; i++) { f = files[i]; st = fs.statSync(path.join(directory, f)); if (st.isDirectory() && this.isSuiteToRun(f)) { nsuites++; dir = path.join(directory, f); if(this.fileToRun) { dir = path.join(dir, this.fileToRun); } suite = new Suite(this, f, dir); this.suites.push(suite); } } udebug.log_detail("Added", nsuites, "suites."); return nsuites; }; Driver.prototype.setSuitesToRun = function(suites) { if(typeof suites === 'string') { this.suitesToRun = suites.split(","); return 1; } return -1; }; Driver.prototype.isSuiteToRun = function(directoryName) { var runSuite = false; if(this.suitesToRun === null) { return true; } this.suitesToRun.forEach(function(s) { if((s === directoryName) || (s === directoryName + path.sep)) { runSuite = true; udebug.log_detail("isSuiteToRun:", directoryName); } }); return runSuite; }; Driver.prototype.listSuites = function() { this.suites.forEach(function(s) { var component = path.basename(path.dirname(path.dirname(s.path))); console.log(component,"\t\t",s.name); }); }; Driver.prototype.disableTest = function(suiteName, fileName, testNamePattern) { this.suites.forEach(function(s) { if(s.name == suiteName) { s.disableTest(fileName, testNamePattern); } }); }; Driver.prototype.disableTestsFromFile = function(dir, f) { var file = path.join(dir, f); var disablerFunction = require(file); disablerFunction(this); }; Driver.prototype.testCompleted = function(testCase) { var suite = testCase.suite; if (suite.testCompleted(testCase)) { // this suite is done; remove it from the list of running suites if (--this.numberOfRunningSuites === 0) { // no more running suites; report and exit clearTimeout(this.timerId); this.allTestsCompleted(); } } }; Driver.prototype.onReportCallback = function() { return; }; Driver.prototype.onAllTestsCompleteCallback = function(userCallback) { userCallback(); }; Driver.prototype.allTestsCompleted = function() { var driver = this; driver.onAllTestsCompleteCallback(function() { driver.reportResultsAndExit(); }); }; Driver.prototype.reportResultsAndExit = function() { var driver = this; driver.exitStatus |= driver.result.report(); this.onReportCallback(); this.result.reset(); if (driver.allTestsCallback) { driver.allTestsCallback(driver.exitStatus); } else { process.exit(driver.exitStatus); } }; Driver.prototype.runAllTests = function(allTestsCallback) { this.allTestsCallback = allTestsCallback; var i; var driver = this; /* Should we show the help text and exit? */ if(this.abortAndExit) { this.flagHandler.usage(0); } /* Or list suites and exit? */ if(this.listSuitesAndExit) { this.listSuites(); process.exit(0); } /* Create tests */ for(i = 0; i < this.suites.length ; i++) { this.suites[i].createTests(); } /* Set Timeout */ function onTimeout() { console.log("DRIVER TIMED OUT after", driver.timeoutMillis, "msec."); driver.reportResultsAndExit(); } if(this.timeoutMillis > 0) { this.timerId = setTimeout(onTimeout, this.timeoutMillis); } /* Now start running tests */ udebug.log_detail("Starting tests from", this.suites.length, "suites"); this.numberOfRunningSuites = this.suites.length; for(i = 0; i < this.suites.length ; i++) { if (! this.suites[i].runTests(this.result)) { this.numberOfRunningSuites--; } } /* If we did not start any suites, exit now */ if (this.numberOfRunningSuites === 0) { this.reportResultsAndExit(); } }; Driver.prototype.setCommandLineFlags = function() { var opts = this.flagHandler, driver = this; opts.addOption(new CommandLine.Option( "-h", "--help", "print this message", function() { driver.abortAndExit = true; return 0; } )); opts.addOption(new CommandLine.Option( "-l", "--list", "just list test suites", function() { driver.listSuitesAndExit = true; return 0; } )); opts.addOption(new CommandLine.Option( "-d", "--debug", "enable debug output", function() { unified_debug.level_debug(); unified_debug.on(); return 0; } )); opts.addOption(new CommandLine.Option( null, "--detail", "enable detailed debug output", function() { unified_debug.level_detail(); unified_debug.on(); return 0; } )); opts.addOption(new CommandLine.Option( "-df=<sourcefile>", null, "enable all debug output from <sourcefile>", function(thisArg) { unified_debug.on(); unified_debug.set_file_level(thisArg, 5); return 1; } )); opts.addOption(new CommandLine.Option( "-t", "--trace", "print stack trace from failing tests", function() { driver.result.listener.printStackTraces = true; return 0; } )); opts.addOption(new CommandLine.Option( null, "--skip-smoke", "do not run SmokeTest", function() { driver.skipSmokeTest = true; return 0; } )); opts.addOption(new CommandLine.Option( null, "--skip-clear", "do not run ClearSmokeTest", function() { driver.skipClearSmokeTest = true; return 0; } )); // --timeout takes a value in milliseconds opts.addOption(new CommandLine.Option( null, "--timeout <msec>", "set timeout in msec.", function(thisArg) { if(thisArg) { driver.timeoutMillis = thisArg; return 1; } return -1; // timeout value is required } )); // --failed and --quiet both imply 10 sec. timeout: opts.addOption(new CommandLine.Option( "-q", "--quiet", "do not print individual test results", function() { driver.result.listener = new Listener.QuietListener(); driver.timeoutMillis = 10000; return 0; } )); opts.addOption(new CommandLine.Option( "-f", "--failed", "suppress passed tests, print failures only", function() { driver.result.listener = new Listener.FailOnlyListener(); driver.timeoutMillis = 10000; return 0; } )); opts.addOption(new CommandLine.Option( null, "--suite <suite>", "only run the named suite", function(thisArg) { return driver.setSuitesToRun(thisArg); } )); opts.addOption(new CommandLine.Option( null, "--suites <suite,suite,...>", "only run the named suites", function(thisArg) { return driver.setSuitesToRun(thisArg); } )); opts.addOption(new CommandLine.Option( null, "--test <testFile>", "only run the named test file", function(thisArg) { var suite; if(thisArg) { if(! thisArg.match(/\.js$/)) { if(thisArg.match(/Test$/)) { thisArg += ".js"; } else { thisArg += "Test.js"; } } driver.fileToRun = path.basename(thisArg); suite = path.dirname(thisArg); if(suite) { driver.suitesToRun = [ suite ]; } return 1; } return -1; // argument is required } )); opts.addOption(new CommandLine.Option( null, "--case <n,m,...>","only run test cases numbered n, m, etc. in <testFile>\n", function(thisArg) { if(thisArg) { driver.testInFile = thisArg; return 1; } return -1; // test number is required } )); }; module.exports = Driver;