Skip to content
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
wants to merge 45 commits into from
Closed
Show file tree
Hide file tree
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 Aug 5, 2016
f4d6f45
Move cucumber code around
TheMarex Aug 5, 2016
0fa9c80
First iteration
TheMarex Aug 18, 2016
fb9fe01
Next iteration
TheMarex Aug 21, 2016
5923b01
Remove unnecessary callbacks
TheMarex Aug 21, 2016
a34cea3
Small fixes
TheMarex Aug 21, 2016
10a1044
Another round of moving stuff
TheMarex Aug 21, 2016
79feb14
It's alive
TheMarex Aug 22, 2016
dfc1f4a
Output more log output
TheMarex Aug 22, 2016
1e517f5
Fix eslint
TheMarex Aug 22, 2016
231ce8d
Remove lingering sync code
TheMarex Aug 22, 2016
a6a0ddb
Add missing files
TheMarex Aug 22, 2016
fe1e060
Simplify the name normalization regexp
TheMarex Aug 22, 2016
3836b12
Remove logFail and add error handlers
TheMarex Aug 22, 2016
5616be2
Remove unused variables
TheMarex Aug 22, 2016
29fbd43
Make sure all log files are written and increase maxBuffer
TheMarex Aug 24, 2016
e9a0d32
Deal with partial failtures
TheMarex Aug 25, 2016
ac1e4a0
Swtich logging to writeStream
TheMarex Aug 25, 2016
0922635
Include line number in scenario name
TheMarex Aug 25, 2016
b7895ac
Fix name normalization
TheMarex Aug 25, 2016
2e33aca
More fixes
TheMarex Aug 29, 2016
681cda4
Replace explicit exit code checks with success/error
TheMarex Aug 29, 2016
db0aaf9
Move speed, raster and penalty file to scenario cache
TheMarex Aug 29, 2016
29f2d14
Fix raster source loading
TheMarex Aug 29, 2016
bd94dff
it passes, finally
TheMarex Aug 29, 2016
6b2fa4c
Fix logging
TheMarex Aug 29, 2016
92c7071
Create all file system paths upfront
TheMarex Aug 29, 2016
2e6d3d3
Fix eslint
TheMarex Aug 30, 2016
2e80e80
Add cache invalidation
TheMarex Aug 30, 2016
0cbd37c
fix eslint intendation errors
Aug 30, 2016
1978bf7
fix queue usage
Aug 30, 2016
6ec38cb
handle errors in routability
Aug 30, 2016
d94ece2
ensure cucumber tests use ./test/.stxxl for best speed
Aug 30, 2016
87fcb3b
set stxxl config in env.js
Aug 30, 2016
d80ddc6
Use execFile that does not spawn a shell
oxidase Aug 31, 2016
8736575
fix the passing of STXXLCFG value
Sep 1, 2016
7d3bd69
shut down osrm-routed in After hook
Sep 1, 2016
e017529
avoid potential double callback call
Sep 1, 2016
dbd605d
fix unstable hashing of files
Sep 1, 2016
b595084
Make log stream local to children processes
oxidase Sep 3, 2016
9f4c880
Fix stamp file names data race
oxidase Sep 3, 2016
dd08ab2
Set 30 seconds timeout for MD5 hashing in BeforeFeatures
oxidase Sep 5, 2016
8b654a2
Print exit reason with signals information
oxidase Sep 5, 2016
6abc132
Avoid osrm-routed shutdown in After hook
oxidase Sep 5, 2016
f6e2ba0
Make a local copy of parameters to avoid inconsistency at timeouts
oxidase Sep 16, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions cucumber.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
module.exports = {
default: '--require features --tags ~@stress --tags ~@todo',
verify: '--require features --tags ~@todo --tags ~@bug --tags ~@stress -f progress',
jenkins: '--require features --tags ~@todo --tags ~@bug --tags ~@stress --tags ~@options -f progress',
bugs: '--require features --tags @bug',
todo: '--require features --tags @todo',
all: '--require features'
default: '--strict --tags ~@stress --tags ~@todo --require features/support --require features/step_definitions',
verify: '--strict --tags ~@stress --tags ~@todo -f progress --require features/support --require features/step_definitions',
todo: '--strict --tags @todo --require features/support --require features/step_definitions',
all: '--strict --require features/support --require features/step_definitions'
Copy link

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?

Copy link

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.

Copy link
Member Author

@TheMarex TheMarex Aug 22, 2016

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)

Copy link

@MoKob MoKob Aug 22, 2016

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 as broken 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.

}


Expand Down
9 changes: 4 additions & 5 deletions features/car/traffic_speeds.feature
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Feature: Traffic - speeds
| fb | primary |
Given the profile "testbot"
Given the extract extra arguments "--generate-edge-lookup"
Given the contract extra arguments "--segment-speed-file speeds.csv"
Given the contract extra arguments "--segment-speed-file {speeds_file}"
Given the speed file
"""
1,2,0
Expand Down Expand Up @@ -69,7 +69,7 @@ Feature: Traffic - speeds
| fb | primary |
Given the profile "testbot"
Given the extract extra arguments "--generate-edge-lookup"
Given the contract extra arguments "--segment-speed-file speeds.csv"
Given the contract extra arguments "--segment-speed-file {speeds_file}"
Given the speed file
"""
1,2,0
Expand Down Expand Up @@ -112,7 +112,6 @@ Feature: Traffic - speeds
| fb | primary |
Given the profile "testbot"
Given the extract extra arguments "--generate-edge-lookup"
Given the contract extra arguments "--segment-speed-file speeds.csv"
Given the speed file
"""
1,2,-10
Expand All @@ -123,6 +122,6 @@ Feature: Traffic - speeds
4,1,-5
"""
And the data has been extracted
When I run "osrm-contract --segment-speed-file speeds.csv {extracted_base}.osrm"
When I try to run "osrm-contract --segment-speed-file {speeds_file} {processed_file}"
And stderr should contain "malformed"
And it should exit with code not 0
And it should exit with an error
4 changes: 2 additions & 2 deletions features/car/traffic_turn_penalties.feature
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Feature: Traffic - turn penalties
8,11,12,23
1,4,5,-0.2
"""
And the contract extra arguments "--turn-penalty-file penalties.csv"
And the contract extra arguments "--turn-penalty-file {penalties_file}"
When I route I should get
| from | to | route | speed | time |
| a | h | ad,dhk,dhk | 63 km/h | 11.5s +-1 |
Expand All @@ -81,7 +81,7 @@ Feature: Traffic - turn penalties
# double left - hdc penalty ever so slightly higher than imn; forces all the way around

Scenario: Too-negative penalty clamps, but does not fail
Given the contract extra arguments "--turn-penalty-file penalties.csv"
Given the contract extra arguments "--turn-penalty-file {penalties_file}"
And the profile "testbot"
And the turn penalty file
"""
Expand Down
4 changes: 2 additions & 2 deletions features/guidance/anticipate-lanes.feature
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ Feature: Turn Lane Guidance
| waypoints | route | turns | lanes |
| a,e | main,main,main,main | depart,use lane straight,continue right,arrive | ,left:false straight:false straight:false straight:false straight:true straight:true right:false,straight:false straight:false right:false right:true right:true, |

@anticipate @todo @bug @2661
@anticipate @todo @2661
Scenario: Anticipate with lanes in roundabout: roundabouts as the unit of anticipation
Given the node map
| | | e | | |
Expand Down Expand Up @@ -667,7 +667,7 @@ Feature: Turn Lane Guidance
| a,f | abc,bdeh,feg,feg | depart,turn right,turn right,arrive | ,none:false none:false right:false right:true,left:false none:false none:false right:true, |

@anticipate
Scenario: Tripple Right keeping Left
Scenario: Triple Right keeping Left
Given the node map
| a | | | | b | | i |
| | | | | | | |
Expand Down
2 changes: 1 addition & 1 deletion features/guidance/turn-lanes.feature
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ Feature: Turn Lane Guidance
| a,d | hwy,hwy | depart,arrive | , |
| a,e | hwy,ramp,ramp | depart,off ramp slight right,arrive | ,straight:false straight:false straight;slight right:true slight right:true, |

@bug @todo
@todo
Scenario: Turning Off Ramp
Given the node map
| | a | |
Expand Down
31 changes: 31 additions & 0 deletions features/lib/hash.js
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'));
});
}
};
8 changes: 2 additions & 6 deletions features/support/build_osm.js → features/lib/osm.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
'use strict';

var builder = require('xmlbuilder');

var ensureDecimal = (i) => {
if (parseInt(i) === i) return i.toFixed(1);
else return i;
};
const builder = require('xmlbuilder');
const ensureDecimal = require('./utils').ensureDecimal;

class DB {
constructor () {
Expand Down
169 changes: 169 additions & 0 deletions features/lib/osrm_loader.js
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;
54 changes: 54 additions & 0 deletions features/lib/table_diff.js
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';
};
13 changes: 13 additions & 0 deletions features/lib/try_connect.js
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.'));
});
}

17 changes: 17 additions & 0 deletions features/lib/utils.js
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);
}
};
Loading