@@ -680,9 +680,9 @@ function cleanTestDirs() {
680680}
681681
682682// used to pass data from jake command line directly to run.js
683- function writeTestConfigFile ( tests , light , testConfigFile ) {
684- console . log ( 'Running test(s): ' + tests ) ;
685- var testConfigContents = JSON . stringify ( { test : [ tests ] , light : light } ) ;
683+ function writeTestConfigFile ( tests , light , taskConfigsFolder , workerCount , testConfigFile ) {
684+ var testConfigContents = JSON . stringify ( { test : tests ? [ tests ] : undefined , light : light , workerCount : workerCount , taskConfigsFolder : taskConfigsFolder } ) ;
685+ console . log ( 'Running tests with config: ' + testConfigContents ) ;
686686 fs . writeFileSync ( 'test.config' , testConfigContents ) ;
687687}
688688
@@ -692,7 +692,7 @@ function deleteTemporaryProjectOutput() {
692692 }
693693}
694694
695- function runConsoleTests ( defaultReporter , defaultSubsets ) {
695+ function runConsoleTests ( defaultReporter , runInParallel ) {
696696 cleanTestDirs ( ) ;
697697 var debug = process . env . debug || process . env . d ;
698698 tests = process . env . test || process . env . tests || process . env . t ;
@@ -701,9 +701,22 @@ function runConsoleTests(defaultReporter, defaultSubsets) {
701701 if ( fs . existsSync ( testConfigFile ) ) {
702702 fs . unlinkSync ( testConfigFile ) ;
703703 }
704+ var workerCount , taskConfigsFolder ;
705+ if ( runInParallel ) {
706+ // generate name to store task configuration files
707+ var prefix = os . tmpdir ( ) + "/ts-tests" ;
708+ var i = 1 ;
709+ do {
710+ taskConfigsFolder = prefix + i ;
711+ i ++ ;
712+ } while ( fs . existsSync ( taskConfigsFolder ) ) ;
713+ fs . mkdirSync ( taskConfigsFolder ) ;
714+
715+ workerCount = process . env . workerCount || os . cpus ( ) . length ;
716+ }
704717
705- if ( tests || light ) {
706- writeTestConfigFile ( tests , light , testConfigFile ) ;
718+ if ( tests || light || taskConfigsFolder ) {
719+ writeTestConfigFile ( tests , light , taskConfigsFolder , workerCount , testConfigFile ) ;
707720 }
708721
709722 if ( tests && tests . toLocaleLowerCase ( ) === "rwc" ) {
@@ -717,61 +730,93 @@ function runConsoleTests(defaultReporter, defaultSubsets) {
717730
718731 // timeout normally isn't necessary but Travis-CI has been timing out on compiler baselines occasionally
719732 // default timeout is 2sec which really should be enough, but maybe we just need a small amount longer
720- var subsetRegexes ;
721- if ( defaultSubsets . length === 0 ) {
722- subsetRegexes = [ tests ] ;
733+ if ( ! runInParallel ) {
734+ tests = tests ? ' -g "' + tests + '"' : '' ;
735+ var cmd = "mocha" + ( debug ? " --debug-brk" : "" ) + " -R " + reporter + tests + colors + ' -t ' + testTimeout + ' ' + run ;
736+ console . log ( cmd ) ;
737+ exec ( cmd , function ( ) {
738+ runLinter ( ) ;
739+ finish ( ) ;
740+ } , function ( e , status ) {
741+ finish ( status ) ;
742+ } ) ;
743+
723744 }
724745 else {
725- var subsets = tests ? tests . split ( "|" ) : defaultSubsets ;
726- subsetRegexes = subsets . map ( function ( sub ) { return "^" + sub + ".*$" ; } ) ;
727- subsetRegexes . push ( "^(?!" + subsets . join ( "|" ) + ").*$" ) ;
728- }
729- var counter = subsetRegexes . length ;
730- var errorStatus ;
731- subsetRegexes . forEach ( function ( subsetRegex , i ) {
732- tests = subsetRegex ? ' -g "' + subsetRegex + '"' : '' ;
733- var cmd = "mocha" + ( debug ? " --debug-brk" : "" ) + " -R " + reporter + tests + colors + ' -t ' + testTimeout + ' ' + run ;
746+ // run task to load all tests and partition them between workers
747+ var cmd = "mocha " + " -R min " + colors + run ;
734748 console . log ( cmd ) ;
735- function finish ( status ) {
736- counter -- ;
737- // save first error status
738- if ( status !== undefined && errorStatus === undefined ) {
739- errorStatus = status ;
740- }
741-
742- deleteTemporaryProjectOutput ( ) ;
743- if ( counter !== 0 || errorStatus === undefined ) {
744- // run linter when last worker is finished
745- if ( lintFlag && counter === 0 ) {
746- var lint = jake . Task [ 'lint' ] ;
747- lint . addListener ( 'complete' , function ( ) {
749+ exec ( cmd , function ( ) {
750+ // read all configuration files and spawn a worker for every config
751+ var configFiles = fs . readdirSync ( taskConfigsFolder ) ;
752+ var counter = configFiles . length ;
753+ var firstErrorStatus ;
754+ // schedule work for chunks
755+ configFiles . forEach ( function ( f ) {
756+ var configPath = path . join ( taskConfigsFolder , f ) ;
757+ var workerCmd = "mocha" + " -t " + testTimeout + " -R " + reporter + " " + colors + " " + run + " --config='" + configPath + "'" ;
758+ console . log ( workerCmd ) ;
759+ exec ( workerCmd , finishWorker , finishWorker )
760+ } ) ;
761+
762+ function finishWorker ( e , errorStatus ) {
763+ counter -- ;
764+ if ( firstErrorStatus === undefined && errorStatus !== undefined ) {
765+ firstErrorStatus = errorStatus ;
766+ }
767+ if ( counter !== 0 ) {
768+ complete ( ) ;
769+ }
770+ else {
771+ // last worker clean everything and runs linter in case if there were no errors
772+ deleteTemporaryProjectOutput ( ) ;
773+ jake . rmRf ( taskConfigsFolder ) ;
774+ if ( firstErrorStatus === undefined ) {
775+ runLinter ( ) ;
748776 complete ( ) ;
749- } ) ;
750- lint . invoke ( ) ;
777+ }
778+ else {
779+ failWithStatus ( firstErrorStatus ) ;
780+ }
751781 }
752- complete ( ) ;
753- }
754- else {
755- fail ( "Process exited with code " + status ) ;
756782 }
783+ } ) ;
784+ }
785+
786+ function failWithStatus ( status ) {
787+ fail ( "Process exited with code " + status ) ;
788+ }
789+
790+ function finish ( errorStatus ) {
791+ deleteTemporaryProjectOutput ( ) ;
792+ if ( errorStatus !== undefined ) {
793+ failWithStatus ( errorStatus ) ;
757794 }
758- exec ( cmd , function ( ) {
759- finish ( ) ;
760- } , function ( e , status ) {
761- finish ( status ) ;
795+ else {
796+ complete ( ) ;
797+ }
798+ }
799+ function runLinter ( ) {
800+ if ( ! lintFlag ) {
801+ return ;
802+ }
803+ var lint = jake . Task [ 'lint' ] ;
804+ lint . addListener ( 'complete' , function ( ) {
805+ complete ( ) ;
762806 } ) ;
763- } ) ;
807+ lint . invoke ( ) ;
808+ }
764809}
765810
766811var testTimeout = 20000 ;
767812desc ( "Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true." ) ;
768813task ( "runtests-parallel" , [ "build-rules" , "tests" , builtLocalDirectory ] , function ( ) {
769- runConsoleTests ( 'min' , [ 'compiler' , 'conformance' , 'Projects' , 'fourslash' ] ) ;
814+ runConsoleTests ( 'min' , /*runInParallel*/ true ) ;
770815} , { async : true } ) ;
771816
772817desc ( "Runs the tests using the built run.js file. Optional arguments are: t[ests]=regex r[eporter]=[list|spec|json|<more>] d[ebug]=true color[s]=false lint=true." ) ;
773818task ( "runtests" , [ "build-rules" , "tests" , builtLocalDirectory ] , function ( ) {
774- runConsoleTests ( 'mocha-fivemat-progress-reporter' , [ ] ) ;
819+ runConsoleTests ( 'mocha-fivemat-progress-reporter' , /*runInParallel*/ false ) ;
775820} , { async : true } ) ;
776821
777822desc ( "Generates code coverage data via instanbul" ) ;
0 commit comments