-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite cucumber test caching (and support logic) #2795
Closed
Closed
Changes from all commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
26de439
Change sha1 to md5 in cucumber because its faster
TheMarex f4d6f45
Move cucumber code around
TheMarex 0fa9c80
First iteration
TheMarex fb9fe01
Next iteration
TheMarex 5923b01
Remove unnecessary callbacks
TheMarex a34cea3
Small fixes
TheMarex 10a1044
Another round of moving stuff
TheMarex 79feb14
It's alive
TheMarex dfc1f4a
Output more log output
TheMarex 1e517f5
Fix eslint
TheMarex 231ce8d
Remove lingering sync code
TheMarex a6a0ddb
Add missing files
TheMarex fe1e060
Simplify the name normalization regexp
TheMarex 3836b12
Remove logFail and add error handlers
TheMarex 5616be2
Remove unused variables
TheMarex 29fbd43
Make sure all log files are written and increase maxBuffer
TheMarex e9a0d32
Deal with partial failtures
TheMarex ac1e4a0
Swtich logging to writeStream
TheMarex 0922635
Include line number in scenario name
TheMarex b7895ac
Fix name normalization
TheMarex 2e33aca
More fixes
TheMarex 681cda4
Replace explicit exit code checks with success/error
TheMarex db0aaf9
Move speed, raster and penalty file to scenario cache
TheMarex 29f2d14
Fix raster source loading
TheMarex bd94dff
it passes, finally
TheMarex 6b2fa4c
Fix logging
TheMarex 92c7071
Create all file system paths upfront
TheMarex 2e6d3d3
Fix eslint
TheMarex 2e80e80
Add cache invalidation
TheMarex 0cbd37c
fix eslint intendation errors
1978bf7
fix queue usage
6ec38cb
handle errors in routability
d94ece2
ensure cucumber tests use ./test/.stxxl for best speed
87fcb3b
set stxxl config in env.js
d80ddc6
Use execFile that does not spawn a shell
oxidase 8736575
fix the passing of STXXLCFG value
7d3bd69
shut down osrm-routed in After hook
e017529
avoid potential double callback call
dbd605d
fix unstable hashing of files
b595084
Make log stream local to children processes
oxidase 9f4c880
Fix stamp file names data race
oxidase dd08ab2
Set 30 seconds timeout for MD5 hashing in BeforeFeatures
oxidase 8b654a2
Print exit reason with signals information
oxidase 6abc132
Avoid osrm-routed shutdown in After hook
oxidase f6e2ba0
Make a local copy of parameters to avoid inconsistency at timeouts
oxidase File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const crypto = require('crypto'); | ||
const d3 = require('d3-queue'); | ||
|
||
module.exports = { | ||
hashOfFiles: (paths, cb) => { | ||
let queue = d3.queue(); | ||
for (let i = 0; i < paths.length; ++i) { | ||
queue.defer(fs.readFile, paths[i]); | ||
} | ||
queue.awaitAll((err, results) => { | ||
if (err) return cb(err); | ||
let checksum = crypto.createHash('md5'); | ||
for (let i = 0; i < results.length; ++i) { | ||
checksum.update(results[i]); | ||
} | ||
cb(null, checksum.digest('hex')); | ||
}); | ||
}, | ||
|
||
hashOfFile: (path, cb) => { | ||
fs.readFile(path, (err, result) => { | ||
if (err) return cb(err); | ||
let checksum = crypto.createHash('md5'); | ||
checksum.update(result); | ||
cb(null, checksum.digest('hex')); | ||
}); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const util = require('util'); | ||
const Timeout = require('node-timeout'); | ||
const tryConnect = require('../lib/try_connect'); | ||
const errorReason = require('./utils').errorReason; | ||
|
||
class OSRMBaseLoader{ | ||
constructor (scope) { | ||
this.scope = scope; | ||
this.child = null; | ||
} | ||
|
||
launch (callback) { | ||
var limit = Timeout(this.scope.TIMEOUT, { err: new Error('*** Launching osrm-routed timed out.') }); | ||
|
||
var runLaunch = (cb) => { | ||
this.osrmUp(() => { this.waitForConnection(cb); }); | ||
}; | ||
|
||
runLaunch(limit((e) => { if (e) callback(e); else callback(); })); | ||
} | ||
|
||
shutdown (callback) { | ||
if (!this.osrmIsRunning()) return callback(); | ||
|
||
var limit = Timeout(this.scope.TIMEOUT, { err: new Error('*** Shutting down osrm-routed timed out.')}); | ||
|
||
this.osrmDown(limit(callback)); | ||
} | ||
|
||
osrmIsRunning () { | ||
return this.child && !this.child.killed; | ||
} | ||
|
||
osrmDown (callback) { | ||
if (this.osrmIsRunning()) { | ||
this.child.on('exit', (code, signal) => {callback();}); | ||
this.child.kill(); | ||
} else callback(); | ||
} | ||
|
||
waitForConnection (callback) { | ||
var retryCount = 0; | ||
let retry = (err) => { | ||
if (err) { | ||
if (retryCount < 10) { | ||
retryCount++; | ||
setTimeout(() => { tryConnect(this.scope.OSRM_PORT, retry); }, 10); | ||
} else { | ||
callback(new Error("Could not connect to osrm-routed after ten retries.")); | ||
} | ||
} | ||
else | ||
{ | ||
callback(); | ||
} | ||
}; | ||
|
||
tryConnect(this.scope.OSRM_PORT, retry); | ||
} | ||
}; | ||
|
||
class OSRMDirectLoader extends OSRMBaseLoader { | ||
constructor (scope) { | ||
super(scope); | ||
} | ||
|
||
load (inputFile, callback) { | ||
this.inputFile = inputFile; | ||
this.shutdown(() => { | ||
this.launch(callback); | ||
}); | ||
} | ||
|
||
osrmUp (callback) { | ||
if (this.osrmIsRunning()) return callback(new Error("osrm-routed already running!")); | ||
|
||
this.child = this.scope.runBin('osrm-routed', util.format("%s -p %d", this.inputFile, this.scope.OSRM_PORT), this.scope.environment, (err) => { | ||
if (err) { | ||
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd)); | ||
} | ||
}); | ||
callback(); | ||
} | ||
}; | ||
|
||
class OSRMDatastoreLoader extends OSRMBaseLoader { | ||
constructor (scope) { | ||
super(scope); | ||
} | ||
|
||
load (inputFile, callback) { | ||
this.inputFile = inputFile; | ||
|
||
this.loadData((err) => { | ||
if (err) return callback(err); | ||
if (!this.osrmIsRunning()) this.launch(callback); | ||
else { | ||
this.scope.setupOutputLog(this.child, fs.createWriteStream(this.scope.scenarioLogFile, {'flags': 'a'})); | ||
callback(); | ||
} | ||
}); | ||
} | ||
|
||
loadData (callback) { | ||
this.scope.runBin('osrm-datastore', this.inputFile, this.scope.environment, (err) => { | ||
if (err) return callback(new Error('*** osrm-datastore exited with ' + err.code + ': ' + err)); | ||
callback(); | ||
}); | ||
} | ||
|
||
osrmUp (callback) { | ||
if (this.osrmIsRunning()) return callback(); | ||
|
||
this.child = this.scope.runBin('osrm-routed', util.format('--shared-memory=1 -p %d', this.scope.OSRM_PORT), this.scope.environment, (err) => { | ||
if (err) { | ||
throw new Error(util.format('osrm-routed %s: %s', errorReason(err), err.cmd)); | ||
} | ||
}); | ||
|
||
// we call the callback here, becuase we don't want to wait for the child process to finish | ||
callback(); | ||
} | ||
}; | ||
|
||
class OSRMLoader { | ||
constructor (scope) { | ||
this.scope = scope; | ||
this.sharedLoader = new OSRMDatastoreLoader(this.scope); | ||
this.directLoader = new OSRMDirectLoader(this.scope); | ||
this.method = scope.DEFAULT_LOAD_METHOD; | ||
} | ||
|
||
load (inputFile, callback) { | ||
if (this.method === 'datastore') { | ||
this.directLoader.shutdown((err) => { | ||
if (err) return callback(err); | ||
this.loader = this.sharedLoader; | ||
this.sharedLoader.load(inputFile, callback); | ||
}); | ||
} else if (this.method === 'directly') { | ||
this.sharedLoader.shutdown((err) => { | ||
if (err) return callback(err); | ||
this.loader = this.directLoader; | ||
this.directLoader.load(inputFile, callback); | ||
}); | ||
} else { | ||
callback(new Error('*** Unknown load method ' + method)); | ||
} | ||
} | ||
|
||
setLoadMethod (method) { | ||
this.method = method; | ||
} | ||
|
||
shutdown (callback) { | ||
if (!this.loader) return callback(); | ||
|
||
this.loader.shutdown(callback); | ||
} | ||
|
||
up () { | ||
return this.loader ? this.loader.osrmIsRunning() : false; | ||
} | ||
}; | ||
|
||
module.exports = OSRMLoader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
'use strict'; | ||
|
||
var util = require('util'); | ||
var path = require('path'); | ||
var fs = require('fs'); | ||
var chalk = require('chalk'); | ||
|
||
var unescapeStr = (str) => str.replace(/\\\|/g, '\|').replace(/\\\\/g, '\\'); | ||
|
||
module.exports = function (expected, actual) { | ||
let headers = expected.raw()[0]; | ||
let expected_keys = expected.hashes(); | ||
let diff = []; | ||
let hasErrors = false; | ||
|
||
var good = 0, bad = 0; | ||
|
||
expected_keys.forEach((row, i) => { | ||
var rowError = false; | ||
|
||
for (var j in row) { | ||
if (unescapeStr(row[j]) != actual[i][j]) { | ||
rowError = true; | ||
hasErrors = true; | ||
break; | ||
} | ||
} | ||
|
||
if (rowError) { | ||
bad++; | ||
diff.push(Object.assign({}, row, {c_status: 'undefined'})); | ||
diff.push(Object.assign({}, actual[i], {c_status: 'comment'})); | ||
} else { | ||
good++; | ||
diff.push(row); | ||
} | ||
}); | ||
|
||
if (!hasErrors) return null; | ||
|
||
var s = ['Tables were not identical:']; | ||
s.push(headers.map(key => ' ' + key).join(' | ')); | ||
diff.forEach((row) => { | ||
var rowString = '| '; | ||
headers.forEach((header) => { | ||
if (!row.c_status) rowString += chalk.green(' ' + row[header] + ' | '); | ||
else if (row.c_status === 'undefined') rowString += chalk.yellow('(-) ' + row[header] + ' | '); | ||
else rowString += chalk.red('(+) ' + row[header] + ' | '); | ||
}); | ||
s.push(rowString); | ||
}); | ||
|
||
return s.join('\n') + '\nTODO this is a temp workaround waiting for https://github.com/cucumber/cucumber-js/issues/534'; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
'use strict'; | ||
|
||
const net = require('net'); | ||
const Timeout = require('node-timeout'); | ||
|
||
module.exports = function tryConnect(port, callback) { | ||
net.connect({ port: port, host: '127.0.0.1' }) | ||
.on('connect', () => { callback(); }) | ||
.on('error', () => { | ||
callback(new Error('Could not connect.')); | ||
}); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
'use strict'; | ||
|
||
const util = require('util'); | ||
|
||
module.exports = { | ||
|
||
ensureDecimal: (i) => { | ||
if (parseInt(i) === i) return i.toFixed(1); | ||
else return i; | ||
}, | ||
|
||
errorReason: (err) => { | ||
return err.signal ? | ||
util.format('killed by signal %s', err.signal) : | ||
util.format('exited with code %d', err.code); | ||
} | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are we completely removing the bugs tag, or is this an accident to leave this out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, looks like all bugs are removed below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah this was just a small cleanup.
@todo
and@bug
seem to have served the same function, so it is probably easier to have just one.There are actually quite a few test cases marked as todo that seem weird, we should maybe clean up at some point. (
@stress
also seems to be dysfunctional)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fully agree on the clean-up.
I tried to use todo as
missing feature
and bug asbroken feature
. I don't think that this separation serves much of a purpose, though. I am missing a complete overview if there can be important distinctions in the code-base but I agree that it looks like a good candidate to clean-up.