1 | var async = require('async');
|
2 | var fs = require('fs');
|
3 | var spawn = require('child_process').spawn;
|
4 | var EventEmitter = require('events').EventEmitter;
|
5 | var util = require('util');
|
6 | var helper = require('./helper.js');
|
7 |
|
8 | util.inherits(Antr, EventEmitter);
|
9 |
|
10 | function Antr (options, cb) {
|
11 | var self = this;
|
12 | this._cb = cb || null;
|
13 |
|
14 | options = options || {};
|
15 | this._options = {
|
16 | dirname: options.dirname || '.',
|
17 | filter: options.filter || /^(?!\.)(.+)\.js$/,
|
18 | batchSize: options.batchSize || 8,
|
19 | timeout: (isNaN(parseInt(options.timeout)) )? 30000 : parseInt(options.timeout) * 1000,
|
20 | listFiles: options.listFiles || false,
|
21 | progressBar: (options.progressBar == false) ? false : true,
|
22 | succinct: (options.succinct == true) ? true : false
|
23 | }
|
24 | this._stats = {
|
25 | failed: 0,
|
26 | passed: 0,
|
27 | total: 0,
|
28 | failRate: 0,
|
29 | failedTests: [],
|
30 | passedTests: [],
|
31 | timeTaken: null
|
32 | }
|
33 | }
|
34 |
|
35 | Antr.prototype.run = function() {
|
36 | var self = this;
|
37 |
|
38 | self.getFiles(function (err, files) {
|
39 | if(files && files.length == 0 || !files) {
|
40 | self.emit('complete', {code: 1, message: 'No files found.'});
|
41 | if (self._cb !== null) self._cb('ERROR: No files found.', self._stats);
|
42 | } else {
|
43 | self.emit('start', files);
|
44 |
|
45 | var stack = [];
|
46 | var complete = [];
|
47 | var totalTests = files.length;
|
48 |
|
49 | async.eachLimit(files, self._options.batchSize, function (item, cb) {
|
50 | self.runSingleTest(item, self, cb);
|
51 | }, function (err) {
|
52 | self.emit('complete', {code: 0, message: ''});
|
53 | if (self._cb !== null) {
|
54 | if(self._stats.failed == 0) {
|
55 | self._cb(null, self._stats);
|
56 | } else {
|
57 | self._cb('ERROR: ' + self._stats.failed + ' tests failed.', self._stats);
|
58 | }
|
59 | }
|
60 | })
|
61 | }
|
62 | });
|
63 | }
|
64 |
|
65 | Antr.prototype.runSingleTest = function(item, self, callback){
|
66 | var runTest = spawn(process.execPath, [ item ]);
|
67 | var storedData = [];
|
68 |
|
69 | var timeout = setTimeout(function () {
|
70 | storedData.push({type: 'timeout', data: 'ERROR: No response received from test after ' + (self._options.timeout / 1000) + ' seconds.'});
|
71 | var data = {item: item, code: 1, data: storedData};
|
72 | self.updateStats(data);
|
73 | self.emit('fileComplete', 1, item, storedData);
|
74 | runTest.removeListener('exit', onExit);
|
75 | runTest.stdout.removeListener('data', outOnData);
|
76 | runTest.stderr.removeListener('data', errOnData);
|
77 | return callback(null, data);
|
78 | }, this._options.timeout);
|
79 |
|
80 | var outOnData = function (data) {
|
81 | storedData.push({type: 'stdout', data: data});
|
82 | };
|
83 | var errOnData = function (data) {
|
84 | storedData.push({type: 'stderr', data: data});
|
85 | };
|
86 |
|
87 | runTest.stdout.setEncoding('utf8');
|
88 | runTest.stdout.on('data', outOnData);
|
89 |
|
90 | runTest.stderr.setEncoding('utf8');
|
91 | runTest.stderr.on('data', errOnData);
|
92 |
|
93 | var onExit = function(code, signal){
|
94 | var data = { item: item, code: code, data: storedData };
|
95 | self.updateStats(data);
|
96 | self.emit('fileComplete', code, item, storedData);
|
97 | clearTimeout(timeout);
|
98 | return callback(null, data);
|
99 | }
|
100 |
|
101 | runTest.on('exit', onExit);
|
102 | }
|
103 |
|
104 | Antr.prototype.updateStats = function(data) {
|
105 | if(!data) return;
|
106 | if(data.code == 0) {
|
107 | this._stats.passed++;
|
108 | this._stats.passedTests.push(data.item);
|
109 | } else {
|
110 | this._stats.failed++;
|
111 | this._stats.failedTests.push(data.item);
|
112 | }
|
113 | this._stats.total++;
|
114 | this._stats.failRate = (this._stats.failed / this._stats.total).toFixed(1) * 100;
|
115 | }
|
116 |
|
117 | Antr.prototype.setTime = function(value) {
|
118 | this._stats.timeTaken = value;
|
119 | }
|
120 |
|
121 | Antr.prototype.getFiles = function (cb) {
|
122 | var self = this;
|
123 |
|
124 | var dirs = ( this._options.dirname instanceof Array ) ? this._options.dirname : [this._options.dirname];
|
125 |
|
126 | async.map(dirs, this.findFiles.bind(this), function(err, results){
|
127 | results = results.filter(function(n){return n;});
|
128 | var files = helper.concatArray(results);
|
129 | if( self._options.listFiles ) console.log('Files going to be run: ', files);
|
130 | cb(null, files);
|
131 | });
|
132 | }
|
133 |
|
134 | Antr.prototype.findFiles = function(dir, cb){
|
135 | var self = this;
|
136 | helper.walk(dir, function (err, files) {
|
137 | if( err ) return cb(err, null);
|
138 | async.filter(files, function (item, callback) {
|
139 | var split = item.split('/');
|
140 | callback(self._options.filter.test(split[split.length - 1]));
|
141 | }, function (filteredFiles) {
|
142 | cb(null, filteredFiles);
|
143 | });
|
144 | });
|
145 | }
|
146 |
|
147 | module.exports = Antr;
|