diff --git a/js/Gruntfile.js b/js/Gruntfile.js index d1bd95a..17b311e 100644 --- a/js/Gruntfile.js +++ b/js/Gruntfile.js @@ -49,6 +49,7 @@ module.exports = grunt => { const server = new ContinuousServer( useRootDir ); server.startServer( port ); server.generateReportLoop(); + server.computeWeightsLoop(); if ( snapshot ) { server.createSnapshotLoop(); diff --git a/js/server/ContinuousServer.js b/js/server/ContinuousServer.js index d6e90ad..8261ccb 100644 --- a/js/server/ContinuousServer.js +++ b/js/server/ContinuousServer.js @@ -334,14 +334,10 @@ class ContinuousServer { * @returns {number} */ getTestWeight( test ) { - const lastTestedIndex = _.findIndex( this.snapshots, snapshot => { - const snapshotTest = snapshot.findTest( test.names ); - return snapshotTest && snapshotTest.results.length > 0; - } ); - const lastFailedIndex = _.findIndex( this.snapshots, snapshot => { - const snapshotTest = snapshot.findTest( test.names ); - return snapshotTest && _.some( snapshotTest.results, testResult => !testResult.passed ); - } ); + const snapshotTests = this.snapshots.map( snapshot => snapshot.findTest( test.names ) ).filter( test => !!test ); + + const lastTestedIndex = _.findIndex( snapshotTests, snapshotTest => snapshotTest.results.length > 0 ); + const lastFailedIndex = _.findIndex( snapshotTests, snapshotTest => _.some( snapshotTest.results, testResult => !testResult.passed ) ); let weight = test.priority; @@ -387,6 +383,16 @@ class ContinuousServer { return weight; } + /** + * Recomputes the desired weights for all recent tests. + * @private + */ + computeRecentTestWeights() { + this.snapshots.slice( 0, 2 ).forEach( snapshot => snapshot.tests.forEach( test => { + test.weight = this.getTestWeight( test ); + } ) ); + } + /** * Picks a test based on the tests' relative weights. * @public @@ -397,7 +403,7 @@ class ContinuousServer { weightedSampleTest( tests ) { assert( tests.length ); - const weights = tests.map( test => this.getTestWeight( test ) ); + const weights = tests.map( test => test.weight ); const totalWeight = _.sum( weights ); const cutoffWeight = totalWeight * Math.random(); @@ -477,6 +483,8 @@ class ContinuousServer { await snapshot.create( true ); this.snapshots.push( snapshot ); + + this.computeRecentTestWeights(); } while ( !this.useRootDir ) { @@ -528,6 +536,8 @@ class ContinuousServer { this.snapshots.pop(); } + this.computeRecentTestWeights(); + this.saveToFile(); this.setStatus( 'Removing old snapshot files' ); @@ -629,9 +639,25 @@ class ContinuousServer { } } + /** + * Starts computing weights for tests. + * @public + */ + async computeWeightsLoop() { + while ( true ) { // eslint-disable-line + try { + this.computeRecentTestWeights(); + } + catch ( e ) { + this.setError( `weights error: ${e}` ); + } + + await sleep( 30 * 1000 ); + } + } + /** * Starts generating reports from the available data. - * * @public */ async generateReportLoop() { @@ -688,7 +714,7 @@ class ContinuousServer { for ( const names of testNames ) { const test = this.snapshots[ 0 ] && this.snapshots[ 0 ].findTest( names ); if ( test ) { - testWeights.push( Math.ceil( this.getTestWeight( test ) * 100 ) / 100 ); + testWeights.push( Math.ceil( test.weight * 100 ) / 100 ); } else { testWeights.push( 0 ); diff --git a/js/server/Snapshot.js b/js/server/Snapshot.js index 3737d3c..86c87cd 100644 --- a/js/server/Snapshot.js +++ b/js/server/Snapshot.js @@ -125,6 +125,12 @@ class Snapshot { return new Test( this, description, lastRepoTimestamps[ potentialRepo ] || 0, lastRunnableTimestamps[ potentialRepo ] || 0 ); } ); + // @public {Object.} - ephemeral, we use this.tests for saving things + this.testMap = {}; + this.tests.forEach( test => { + this.testMap[ test.nameString ] = test; + } ); + this.constructed = true; } @@ -150,8 +156,7 @@ class Snapshot { * @returns {Test|null} */ findTest( names ) { - // TODO: can increase performance with different lookups (e.g. binary?) - return _.find( this.tests, test => _.isEqual( test.names, names ) ); + return this.testMap[ Test.namesToNameString( names ) ] || null; } /** diff --git a/js/server/Test.js b/js/server/Test.js index c521dd4..bcd6b9d 100644 --- a/js/server/Test.js +++ b/js/server/Test.js @@ -48,6 +48,9 @@ class Test { // @public {Array.} this.names = description.test; + // @public {string} - Used for faster lookups, single tests, etc. - ephemeral + this.nameString = Test.namesToNameString( this.names ); + // @public {string} this.type = description.type; @@ -57,6 +60,9 @@ class Test { // @public {number} this.priority = 1; + // @public {number} - ephemeral + this.weight = 1; // a default so things will work in case it isn't immediately set + if ( description.priority ) { assert( typeof description.priority === 'number', 'priority should be a number' ); @@ -223,6 +229,17 @@ class Test { }; } + /** + * Returns a single string from a list of names + * @public + * + * @param {Array.} names + * @returns {string} + */ + static namesToNameString( names ) { + return names.join( '.' ); + } + /** * Creates a pojo-style object for saving/restoring * @public