jones-test/lib/Suite.js (236 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 path = require("path"),
fs = require("fs"),
assert = require("assert"),
udebug = require("unified_debug").getLogger("Suite.js");
var re_matching_test_case = /Test\.js$/;
/** Suite
* A suite consists of all test cases in all tests in a single directory
*
*/
function Suite(driver, name, suiteDir) {
this.driver = driver;
this.name = name;
this.path = "";
this.tests = [];
this.disabledTests = {};
this.smokeTest = {};
this.smokeTestHasFailed = null;
this.serialTests = [];
this.clearSmokeTest = {};
this.concurrentTests = [];
this.firstConcurrentTestIndex = -1;
this.firstSerialTestIndex = -1;
this.nextSerialTestIndex = -1;
this.currentTest = 0;
this.numberOfConcurrentTests = 0;
this.numberOfConcurrentTestsCompleted = 0;
this.numberOfSerialTests = 0;
if(typeof suiteDir === 'string') {
this.path = path.resolve(driver.baseDirectory, suiteDir);
}
udebug.log_detail("New Suite:", this.name, "from", this.path);
}
Suite.prototype.addTest = function(filename, test) {
udebug.log(this.name, "adding test", test.name);
test.filename = path.resolve(this.path, filename);
test.suite = this;
test.reset();
this.tests.push(test);
if(this.disabledTests[filename] &&
this.disabledTests[filename].test(test.name))
test.enabled = false;
};
Suite.prototype.disableTest = function(fileName, testNamePattern) {
this.disabledTests[fileName] = testNamePattern;
};
/* addTestsFromFile(fileName, onlyTests)
onlyTests is a string containing a comma separated list of
test numbers. If set, only those elements of the test array are added.
*/
Suite.prototype.addTestsFromFile = function(fileName, onlyTests) {
var f, t, i, j, k, testList, testHash;
f = path.join(this.path, fileName);
if(onlyTests) {
onlyTests = String(onlyTests);
testList = onlyTests.split(",");
testHash = [];
for(i = 0 ; i < testList.length ; i ++) {
k = Number(testList[i]) - 1;
testHash[k] = 1;
}
}
if(re_matching_test_case.test(fileName)) {
t = require(f);
if(typeof(t.tests) === 'object' && t.tests instanceof Array) {
for(j = 0 ; j < t.tests.length ; j++) {
if(onlyTests === null || testHash[j] === 1) {
this.addTest(fileName, t.tests[j]);
}
}
}
else if(typeof(t.isTest) === 'function' && t.isTest()) {
this.addTest(fileName, t);
}
else {
console.log("Warning: " + f + " does not export a Test.");
}
}
};
Suite.prototype.createTests = function() {
var stat, suite, i;
udebug.log_detail("createTests for", this.name, "in", this.path);
if(this.path.length) {
stat = fs.statSync(this.path);
if(stat.isFile()) {
var testFile = this.path;
this.path = path.dirname(testFile);
try {
this.addTestsFromFile("SmokeTest.js", null);
} catch(ignore) {}
this.addTestsFromFile(testFile, this.driver.testInFile);
try {
this.addTestsFromFile("ClearSmokeTest.js", null);
} catch(ignore) {}
}
else if(stat.isDirectory()) {
var files = fs.readdirSync(this.path);
for(i = 0; i < files.length ; i++) {
this.addTestsFromFile(files[i], null);
}
}
}
this.tests.forEach(function(t, index) {
t.original = index;
});
this.tests.sort(function(a,b) {
// sort the tests by phase, preserving the original order within each phase
if(a.phase < b.phase) { return -1; }
if(a.phase === b.phase) { return (a.original < b.original)?-1:1; }
return 1;
});
suite = this;
this.tests.forEach(function(t, index) {
t.index = index;
t.suite = suite;
switch(t.phase) {
case 0:
suite.smokeTest = t;
break;
case 1:
suite.concurrentTests.push(t);
if (suite.firstConcurrentTestIndex === -1) {
suite.firstConcurrentTestIndex = t.index;
}
break;
case 2:
suite.serialTests.push(t);
if (suite.firstSerialTestIndex === -1) {
suite.firstSerialTestIndex = t.index;
}
break;
case 3:
suite.clearSmokeTest = t;
break;
}
});
this.numberOfConcurrentTests = this.concurrentTests.length;
this.numberOfSerialTests = this.serialTests.length;
udebug.log_detail("Suite", this.name, "has",
this.numberOfConcurrentTests, "concurrent tests;",
this.numberOfSerialTests, "serial tests.");
};
Suite.prototype.runTests = function(result) {
var tc;
udebug.log_detail("runTests for", this.name, ":", this.tests.length, "tests");
if (this.tests.length === 0) {
return false;
}
this.currentTest = 0;
tc = this.tests[this.currentTest];
switch (tc.phase) {
case 0:
// smoke test
// start the smoke test
if(this.driver.skipSmokeTest) {
tc.skip("skipping SmokeTest", result);
}
else {
tc.test(result);
}
break;
case 1:
// concurrent test is the first test
// start all concurrent tests
this.startConcurrentTests(result);
break;
case 2:
// serial test is the first test
this.startSerialTests(result);
break;
case 3:
// clear smoke test is the first test
if(this.driver.skipClearSmokeTest) {
tc.skip("skipping ClearSmokeTest", result);
}
else {
tc.test(result);
}
break;
}
return true;
};
Suite.prototype.startConcurrentTests = function(result) {
var skip = this.smokeTestHasFailed;
if (this.firstConcurrentTestIndex !== -1) {
this.concurrentTests.forEach(function(testCase) {
if(skip) {
testCase.skip("(failed SmokeTest)", result);
} else {
testCase.test(result);
}
});
return false;
}
// else:
return this.startSerialTests(result);
};
Suite.prototype.startSerialTests = function(result) {
if (this.firstSerialTestIndex !== -1) {
this.startNextSerialTest(this.firstSerialTestIndex, result);
return false;
}
// else:
return this.startClearSmokeTest(result);
};
Suite.prototype.startClearSmokeTest = function(result) {
if (this.driver.skipClearSmokeTest) {
this.clearSmokeTest.skip("skipping ClearSmokeTest", result);
}
else if (this.clearSmokeTest && this.clearSmokeTest.test) {
this.clearSmokeTest.test(result);
return false;
}
return true;
};
Suite.prototype.startNextSerialTest = function(index, result) {
var testCase = this.tests[index];
if(this.smokeTestHasFailed) {
testCase.skip("(failed SmokeTest)", result);
} else {
testCase.test(result);
}
};
/* Notify the suite that a test has completed.
Returns false if there are more tests to be run,
true if suite is complete.
*/
Suite.prototype.testCompleted = function(testCase) {
var tc, index;
var result = testCase.result;
switch (testCase.phase) {
case 0: // the smoke test completed
this.smokeTestHasFailed = testCase.failed || testCase.skipped;
return this.startConcurrentTests(result);
case 1: // one of the concurrent tests completed
if (++this.numberOfConcurrentTestsCompleted === this.numberOfConcurrentTests) {
return this.startSerialTests(result); // go on to the serial tests
}
return false;
case 2: // one of the serial tests completed
index = testCase.index + 1;
if (index < this.tests.length) {
tc = this.tests[index];
if (tc.phase === 2) {
this.startNextSerialTest(index, result);
}
else if (tc.phase === 3) {
this.startClearSmokeTest(result);
}
return false;
}
/* Done */
return true;
case 3: // the clear smoke test completed
return true;
}
};
module.exports = Suite;